Bonjour,

je fais suite au post résolu situé ici.

j'ai commencé le python il y a environ 2 semaines (la 1ère semaine consistant essentiellement à lire le swaroop et à feuilleter le swinnen), et actuellement, je découvre tkinter en programmant un logiciel destiné à apprendre les 4 opérations pour ma fille (et les filles des autres que ça intéresserait, et même aux garçons, la licence n'étant pas restrictive sur ce sujet )

J'ai déjà bien avancé, mais je n'arrive pas à trouver de doc claire et de préférence en français pour fignoler la mise en page :
- adapter l'intérieur de la fenêtre (y compris la taille des polices si possible) en fonction de sa taille totale : si par exemple on réduit de 50% sa hauteur et sa largeur, il faudrait tout réduire de 50% à l'intérieur
- pour la saisie prénom et date de naissance, je fais une saisie temps réel de l'entry pour ne pas avoir à taper sur la touche entrée, mais il manque toujours le dernier caractère : comment faire ? actualiser le .get() quand l'utilisateur clique sur l'entry de la saisie principale ??? ça marcherait surement mais je ne trouve pas ça très propre... Y a t'il un évènement du style "on quitte l'entry" qui pourrait déclencher le get() ? cela dit, cette question est plus pour le principe car je pense faire une pop-up pour rentrer prénom et date de naissance et l'afficher ensuite comme label dans la fenêtre principale, ce qui ne nécessiterait pas de get() en temps réel.
- toujours pas trouvé l'astuce pour la réduction de taille des entry. j'ai essayé sans succès la méthode geometry ainsi que width

Voici le dernier code en date :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# Necessite : python3 et les librairies tkinter / tix
 
############################################################
### Programme permettant de s'entrainer au calcul mental ###
### en générant aléatoirement des opérations simples à   ###
### résoudre                                             ###
############################################################
 
# Auteur : Spirzouf ( spirzouf at laposte point net )
# Date : 26 jan 2010
# Programme sous licence Creative Commons BY-NC-SA
# http://creativecommons.org/licenses/by-nc-sa/2.0/fr/
# UN GRAND MERCI À PauseKawa POUR SON AIDE, SANS LAQUELLE J'AURAIS SUREMENT MIS PLUSIEURS JOURS DE PLUS POUR PROGRAMMER CECI
# http://www.developpez.net/forums/d867242/autres-langages/python-zope/gui/tkinter/debutant-modifications-dynamiques-fenetre-tkinter/#post4942269
 
# version de développement.
# reste à faire :
# - FAIT ! choix dynamique des intervalles de randomisation
# - FAIT ! possibilité de faire soustraction / multiplication / division
# - FAIT ! possibilité de panacher les exercices (addition suivie d'une soustraction, etc..)
# - apprentissage des tables d'addition, soustraction et multiplication avec base de données donnant pour chaque opération (ex. 5 x 2 = ...)
# - une note sur les 10 derniers essais afin de favoriser la sortie des opérations pour lesquelles l'élève a le moins bien répondu
# Y'a encore du boulot !!!
 
from tkinter import *
import tkinter.font, tkinter.messagebox, tkinter.tix
from random import randint
 
class Application(tkinter.tix.Tk):
    def __init__(self):
        tkinter.tix.Tk.__init__(self)
        # Valeurs par défauts
        # self.mini, self.maxi = 0, 10 # par défaut, les nombres aléatoires seront tirés dans l'intervalle [0,10]
        self.prenom, self.ddn = 'prénom', 'JJ/MM/AAAA'
        # Création des variables du menu
        self.choixAdd, self.choixSous, self.choixMult, self.choixDiv = IntVar(), IntVar(), IntVar(), IntVar()
        self.mini, self.maxi = IntVar(), IntVar()
        # Création et configuration des frames et widgets inclus
        self.miseEnPage()
        # Initialisation des variables du menu
        self.buttonChoixAdd.select()
        self.buttonChoixSous.deselect()
        self.buttonChoixMult.deselect()
        self.buttonChoixDiv.deselect()
        #self.listeMini.entry.insert(0, 0) # par défaut, les nombres aléatoires seront tirés dans l'intervalle [0,10]
        self.listeMaxi.entry.insert(0, 1)
        print(self.listeMini.entry.get() , self.listeMaxi.entry.get())
        # Affichage plein écran
        self.geometry(str(self.winfo_screenwidth())+"x"+str(self.winfo_screenheight())+"+0+0")
        # Création de binds pour enclencher la procédure reponseSaisie lors de l'appuie d'une des 2 touches "entrée"
        # http://www.pythonware.com/library/tkinter/introduction/events-and-bindings.htm
        self.saisie.bind('<Return>', self.reponseSaisie)
        self.saisie.bind('<KP_Enter>', self.reponseSaisie)
        # A FAIRE : bind de validation de la saisie (autoriser uniquement touches 0à9 + sToOpP) 
        self.saisiePrenom.bind('<Key>', self.reponsePrenom)
        self.saisieDDN.bind('<Key>', self.reponseDDN)
        # A FAIRE : binds des Entry du menu
        # Valeurs par défaut et Première initialisation de self.question
        self.initOperation()
 
    def miseEnPage(self): # Création des frames et des widgets
        CouleurFondMenu = 'lightyellow'
        CouleurFondExo = 'lightgreen'
        self.config(bg=CouleurFondMenu)
        # Frames du haut contenant le menu de l'application
        self.menu = Frame(self, width=1920, height=400, bg=CouleurFondMenu)
        self.menu.pack()
        self.menu1 = Frame(self.menu, width=480, height=400, bg=CouleurFondMenu)
        self.menu1.grid(row=1,column=1)
        self.menu2 = Frame(self.menu, width=480, height=400, bg=CouleurFondMenu)
        self.menu2.grid(row=1,column=2)
        self.menu3 = Frame(self.menu, width=480, height=400, bg=CouleurFondMenu)
        self.menu3.grid(row=1,column=3)
        self.menu4 = Frame(self.menu, width=480, height=400, bg=CouleurFondMenu)
        self.menu4.grid(row=1,column=4)
        # Frames du bas contenant la partie exercice et messages de l'application
        self.exo = Frame(self, width=1920, height=600, bg=CouleurFondExo)
        self.exo.pack()
        self.exo1 = Frame(self.exo, width=1920, height=300, bg=CouleurFondExo)
        self.exo1.pack(side=TOP)
        self.exo2 = Frame(self.exo, width=1920, height=300, bg=CouleurFondExo)
        self.exo2.pack()
        self.exo3 = Frame(self.exo, width=1920, height=100, bg=CouleurFondExo)
        self.exo3.pack(side=BOTTOM)
        # Initialisation de la mise en forme tkinter.font (taille des polices)
        tailleMenu = tkinter.font.Font(self)
        tailleMenu.config(size = 20)
        tailleMath = tkinter.font.Font(self)
        tailleMath.config(size = 150)
        tailleMessage = tkinter.font.Font(self)
        tailleMessage.config(size = 40)
        # Initialisation des widgets de la frame menu
        # menu1 ligne 1 : prénom
        self.prenom = Label(self.menu1, text='Mon prénom :')
        self.prenom.config(font = tailleMenu, bg=CouleurFondMenu)
        self.prenom.grid(row=1, column=1, sticky=E)
        self.saisiePrenom = Entry(self.menu1)
        self.saisiePrenom.config(font = tailleMenu, bg=CouleurFondMenu)
        self.saisiePrenom.grid(row=1, column=2)
        # menu1 ligne 2 : date de naissance : servira à créer un profil (associé au prénom)
        # A FAIRE : ComboBoX jour 1-31 - mois en lettres - 19xx/20xx - année 00-99
        self.ddn = Label(self.menu1, text='\nMa date\nde naissance :')
        self.ddn.config(font = tailleMenu, bg=CouleurFondMenu)
        self.ddn.grid(row=2, column=1, sticky=E)
        self.saisieDDN = Entry(self.menu1)
        self.saisieDDN.config(font = tailleMenu, bg=CouleurFondMenu)
        self.saisieDDN.grid(row=2, column=2, sticky=S)
        # menu2 : choix des opérations
        self.buttonChoixAdd = Checkbutton(self.menu2, text='additions (+)', variable=self.choixAdd, selectcolor='red', highlightcolor='green')
        self.buttonChoixAdd.config(font = tailleMenu, bg=CouleurFondMenu)
        self.buttonChoixAdd.grid(column=1, sticky=W)
        self.buttonChoixSous = Checkbutton(self.menu2, text='soustractions (-)', variable=self.choixSous, selectcolor='red', highlightcolor='green')
        self.buttonChoixSous.config(font = tailleMenu, bg=CouleurFondMenu)
        self.buttonChoixSous.grid(column=1, sticky=W)
        self.buttonChoixMult = Checkbutton(self.menu2, text='multiplications (×)', variable=self.choixMult, selectcolor='red', highlightcolor='green')
        self.buttonChoixMult.config(font = tailleMenu, bg=CouleurFondMenu)
        self.buttonChoixMult.grid(column=1, sticky=W)
        self.buttonChoixDiv = Checkbutton(self.menu2, text='divisions (÷)', variable=self.choixDiv, selectcolor='red', highlightcolor='green')
        self.buttonChoixDiv.config(font = tailleMenu, bg=CouleurFondMenu)
        self.buttonChoixDiv.grid(column=1, sticky=W)
        # menu3 (avec 2 nouvelles sous-frames) : A FAIRE binds et évènements
        self.menu31 = Frame(self.menu3) ; self.menu31.pack(side=TOP)
        self.menu32 = Frame(self.menu3) ; self.menu32.pack()
        Label(self.menu31, text='Avec les chiffres', font = tailleMenu, bg=CouleurFondMenu).pack()
        # -> déroulant chiffre self.mini
        Label(self.menu32, text='de', font = tailleMenu, bg=CouleurFondMenu).grid(row=1, column=1)
        self.listeMini = tkinter.tix.ComboBox(self.menu32, editable=1, dropdown=1, variable=self.mini)
        for i in range(0,11):
            self.listeMini.insert(i, i)
        self.listeMini.grid(row=1, column=2)
        # -> déroulant chiffre self.maxi
        Label(self.menu32, text='à', font = tailleMenu, bg=CouleurFondMenu).grid(row=1, column=3)
        self.listeMaxi = tkinter.tix.ComboBox(self.menu32, editable=1, dropdown=1, variable=self.maxi)
        for i in range(0,11):
            self.listeMaxi.insert(i, i)
        self.listeMaxi.grid(row=1, column=4)
        # menu4 : A FAIRE binds et évènements
        Label(self.menu4, text='Faire la table de', font = tailleMenu, bg=CouleurFondMenu).grid(row=1, column=1)
        ChiffreTable= tkinter.tix.IntVar()
        listeChiffreTable = tkinter.tix.ComboBox(self.menu4, editable=1, dropdown=1, variable=ChiffreTable)
        for i in range(0,11):
            listeChiffreTable.insert(i, i)
        listeChiffreTable.grid(row=1, column=2)
        listeChiffreTable.config(bg=CouleurFondMenu)
        Label(self.menu4, text='en', font = tailleMenu, bg=CouleurFondMenu).grid(row=2, column=1)
        TypeTable= tkinter.tix.IntVar()
        listeTypeTable = tkinter.tix.ComboBox(self.menu4, editable=1, dropdown=1, variable=TypeTable)
        listeTypeTable.config(bg=CouleurFondMenu)
        compteur = -1
        for i in ("additions", "soustractions", "multiplication", "divisions"):
            compteur += 1
            listeTypeTable.insert(compteur, i)
        listeTypeTable.grid(row=2, column=2)
        listeTypeTable.entry.delete(0, END) # efface la zone de saisie
        listeTypeTable.entry.insert(0, "additions") # initialise à addition
        listeTypeTable.entry.config(state='readonly')  # zone de saisie en lecture seule
        TypeTable = "additions"
 
        # Initialisation des widgets de la frame exo
        self.title('Additions de chiffres entre 0 et 10')
        self.message = Label(self.exo1)
        self.message.config(font = tailleMessage, text='Ecris ta réponse dans la case jaune', wraplength=1100, bg=CouleurFondExo)
        self.message.grid(row=2, column=1)
        self.question = Label(self.exo2)
        self.question.config(font = tailleMath, bg=CouleurFondExo)
        self.question.grid(row=1, column=1, sticky=W)
        self.saisie = Entry(self.exo2)
        self.saisie.grid(row=1, column=2, sticky=W)
        self.saisie.config(font = tailleMath, bg='lightyellow')
        Label(self.exo3, text="\nPour terminer, écris 'stop' ou cliques sur la croix en haut à droite\n", bg=CouleurFondExo).grid(row=3, column=1)
 
    def initOperation(self): # Procédure d'initialisation de la nouvelle opération à résoudre
        operandes, operandesOK, compteur = ['+', '-', '*', '/'], [], 0
        listeOperations = [self.choixAdd.get(), self.choixSous.get(), self.choixMult.get(), self.choixDiv.get()]
        for i in listeOperations :
            if i == 1:
                operandesOK.append(operandes[compteur])
            compteur += 1
        operande = operandesOK[randint( 1 , len(operandesOK))-1]
        mini, maxi = int(self.listeMini.entry.get()), int(self.listeMaxi.entry.get())
        mini, maxi = min(mini,maxi), max(mini,maxi) # pour les petits qui voudraient faire les malins !
        a, b = randint(mini,maxi), randint(mini,maxi)
        if operande == '/': 
            a *= b # obtenir un résultat entier pour a/b
            b= max(b,1) # empecher la division par zero
        if operande == '-' : # obtenir a≥b pour les soustractions
            a , b = max(a,b) , min (a,b)
        self.questionText = str('{0} {1} {2}'.format (a,operande,b))
        self.resultat = int(eval(self.questionText))
        if operande == '/':
            self.questionText = str('{0} ÷ {1} = '.format (a,b))
        elif operande == '*':
            self.questionText = str('{0} × {1} = '.format (a,b))
        else:
            self.questionText += ' = '            
        self.question.config(text = self.questionText) # Affiche l'opération à résoudre
        self.saisie.delete(0, END) # Vide l'espace de saisie
        self.saisie.focus_set() # Donne le focus à l'espace de saisie
 
    def reponseSaisie(self, event=None):
        ##### event=None car bind retourne un event et nous n'en avons pas besoin ici...
        ##### ... et nécessaire sinon message d'erreur car deux arguments fournis alors que un seul serait attendu.
        # Affichage de l'opération à effectuer au niveau du Label 'question'
        self.question.config(text = self.questionText)
        # Saisie de la réponse
        reponse = self.saisie.get() # Entry retourne toujours un str (Exception, l'utilisation d'un IntVar()/textvariable par exemple)
        if reponse == 'stop': # va afficher un message d'adieu
            self.message.config(text= "D'accord, à bientot", fg='orange')
            tkinter.messagebox.showinfo('Fini !', "J'espère que tu t'es bien amusé, au revoir et à bientôt.")
            self.quit() # on quitte
        reponse = eval(reponse)
        # http://python.developpez.com/faq/?page=Entry#EntryGet
        # test de la réponse et affichage d'un message adapté au niveau du Label 'message'
        if reponse == self.resultat : # va afficher un message de félicitation avec confirmation du résultat
            self.message.config(text= "Bien joué : {0}{1} !\nOn continue avec :".format(self.questionText, self.resultat), fg='darkgreen')
            self.initOperation() # on lance une nouvelle opération à résoudre
        else: # va afficher un message d'erreur avec le résultat
            self.bell() # bip
            self.message.config(text= "Et NON, ce n'est pas {0} !!!\nLa bonne réponse était {1}{2}".format(reponse, self.questionText, self.resultat), fg='red')
            self.initOperation() # on lance une nouvelle opération à résoudre
 
    def reponsePrenom(self, event=None):
        self.prenom = self.saisiePrenom.get() # Saisie du prénom
        print(self.prenom)
 
    def reponseDDN(self, event=None):
        self.ddn = self.saisieDDN.get() # Saisie de la date de naissance
        print(self.ddn)
 
app = Application()
app.mainloop()
# Tout code après le mainloop est exécuté après la destruction de la fenetre
Merci d'avances pour vos lumières !