Exception With Tkinter Callback because loop continues in the background

醉酒当歌 提交于 2020-01-03 05:28:26

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!