问题
Hi people from the forum,
I'm currently a beginner in python and programming in general so please don't shout on me :) I know I have to much global variable and made a lot of mistake.
I am facing a terrible non ending loop problem that doesn't really affect my tkinter window itself, but when closing it is a shame to see this Exception in tkinter callback problem.
Actually I don't know why my batman variable in Valider() function doesn't end all these loops Can someone help me with this one ?
Ps: sorry for French language in the code Thanks
Here is the source code:
from tkinter import*
from random import*
import time
from tkinter import messagebox
from tkinter import ttk
#Initialisation des variables
bonne_reponse=0
mauvaise_reponse=0
nbr_total=0
batman=False
nbr_q=10 # 10 question
t=10 # t est definit le temps que l'utilisateur a pour repondre a la question
#_______________Fonction qui genere 2 nombres au hasard dans des intervalles differents selon la difficultee choisie__________________________#
def Division ():
nbr1 = randint (1,9)
nbr2 = randint (1,9)
div=nbr1*nbr2
calcul_affiche = ("CALCUL : " + str(div) + "/" + str(nbr2) + " =")
label1.configure(text=calcul_affiche)
calcul=nbr1
return calcul
##### Fonction qui demarre le programme et donc qui lance la barre de progression lors du clic sur "Demarrer".
def Démarrer():
global reponse_final
global batman
batman=False
reponse_final=Division()
start_time=time.time()
# defini un temps de demarrage car le module time compte le temps depuis 1974
while batman==False:
now =t-((time.time())-(start_time))
root.update()
#Redefini la valeur de la barre de progression
wq=(now/t)*100
progress["value"] = wq
# Fausse le resultat apres le temps ecoule (avec un calcul improbable)
if wq<=0:
batman=True
if batman==True:
Valider()
##### Fonction de validation
def Valider():
global bonne_reponse
global mauvaise_reponse
global nbr_total
global batman
utilisateur_reponse=entryWidget.get() #recupere la valeur de la boite d'entree
entryWidget.delete(0, END) #supprime ce qu'il y a dans la barre d'entree
# empeche l'utlisateur d'entrer des lettres dans la boite d'entrée
batman=True
try:
if reponse_final != int(utilisateur_reponse):
titre="Réponse"
bon_rep=str("Mauvaise réponse ! La bonne réponse était: "+str(reponse_final))
messagebox.showinfo(titre, bon_rep)
mauvaise_reponse+=1
nbr_total+=1
elif reponse_final== int(utilisateur_reponse):
#messagebox.showinfo("Réponse", "Bonne réponse!")
bonne_reponse+=1
nbr_total+=1
except:
messagebox.showerror("Boite d'entrée", "Temps ecoulé ou Entrez uniquement des nombres")
mauvaise_reponse+=1
nbr_total+=1
#on arrete le jeux lorsque le nombre de question souhaité est atteint
if nbr_total==nbr_q:
exitnote()
Démarrer()
######################Création fenetre principale Tkinter "root" ###################
root = Tk()
root.title("Calcul Mental")
root.configure(bg="gainsboro")
root["padx"] = 60
root["pady"] = 40
# On definit un style et un theme pour les widgets
s = ttk.Style()
s.theme_use('clam')
# Creation du label correspondant a la consigne en debut de page
consigne= ("Cliquez sur démarrer pour commencer. Un nombre illimité de calculs va vous être proposé.")
instructions = ttk.Label(root, text=consigne)
instructions.pack()
label_trait4= ttk.Label(root, text="--------------------------------------------------------------------------------------------------")
label_trait4.pack()
# Création de la barre de progression
s.configure("blue.Horizontal.TProgressbar", foreground='aquamarine3', background='aquamarine3')
progress = ttk.Progressbar(root, style="blue.Horizontal.TProgressbar", orient="horizontal", length=500, mode="determinate")
progress["maximum"] = 100
progress.pack()
### Création d'une boite de texte pour un label texte et la boite d'entree
text_boite= Frame(root)
# Création du label de calcul
label1 = ttk.Label(text_boite, background="white", width=15)
label1["text"] = ""
label1.pack(side=LEFT)
# Création d'un Entry Widget dans text_boite
entryWidget = ttk.Entry(text_boite)
entryWidget['width'] = 50
entryWidget.pack(side=RIGHT)
text_boite.pack()
# Bouton valider
root.bind("<Return>", lambda event: Valider())
btn_valider = ttk.Button(root, text="Valider", command=Valider)
# fait en sorte que quand l'utilisateur appui sur la touche entrer ca lance la fonction valider.
# On rend inutilisable le bouton demarrer apres le 1er clic
def btndemarrer():
btn_démarrer.config(state=DISABLED)
instructions.destroy()
Démarrer()
btn_démarrer = ttk.Button(root, text="Démarrer", command = btndemarrer)
btn_démarrer.pack()
# Affiche la note dans une boite et detruit la fenetre
def exitnote():
global batman
batman=True
try:
note=(bonne_reponse*20/nbr_total)
w=("Votre note est de "+str(note)+"/20.0 ")
messagebox.showinfo("Voici votre note",str(w))
root.destroy()
# Si note n'est pas definit car l'utilisateur n'a pas encore appuye sur Entrer, on affiche le message suivant:
except:
messagebox.showinfo("DEVNOTE","Je respecte votre choix mais vous n'avez meme pas essayé.")
root.destroy()
btn_valider.pack()
btn_arret = ttk.Button(root, text="Arrêt", command=exitnote)
btn_arret.pack()
# On lance la boucle Tkinter qui s'interompt lors de la fermeture de la fenetre
root.mainloop()
Here is the exception :
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python34\lib\tkinter\__init__.py", line 1487, in __call__
return self.func(*args)
File "C:\Users\Thierry\Google Drive\Calcul_Mentalsimple.py", line 145, in <lambda>
root.bind("<Return>", lambda event: Valider())
File "C:\Users\Thierry\Google Drive\Calcul_Mentalsimple.py", line 94, in Valider
Démarrer()
File "C:\Users\Thierry\Google Drive\Calcul_Mentalsimple.py", line 55, in Démarrer
progress["value"] = wq
File "C:\Python34\lib\tkinter\__init__.py", line 1275, in __setitem__
self.configure({key: value})
File "C:\Python34\lib\tkinter\__init__.py", line 1268, in configure
return self._configure('configure', cnf, kw)
File "C:\Python34\lib\tkinter\__init__.py", line 1259, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".59022192"
回答1:
OK, two things here:
1) Your Valider() function needs no arguments according to your code above so you could just simply bind without using lambda
root.bind('<Return>', Valider)
2) When the button/return is triggered and your Valider() is called a reference to the triggering event is passed as far as I know (at least in wxPython it's done this way and short googling gave me the same for tkinter).
That means your triggered function, in this case Valider(), has to take care of that reference as well. According to this your Valider() definition should look like this:
def Valider(event=None):
Defining your Valider() this way handles an incoming reference to an event that triggered the function but gives you the possibility to call the function directly using
Valider()
as the event parameter has a default value set as None
Hope that helps. Greetz :-)
来源:https://stackoverflow.com/questions/30413689/exception-with-tkinter-callback-because-loop-continues-in-the-background