使用Tkinter回调的异常,因为循环在后台继续

时间:2015-05-23 14:12:03

标签: python tkinter python-3.4

嗨,来自论坛的人,

我目前是python和编程的初学者,所以请不要对我大喊大叫:)我知道我有很多全局变量而且犯了很多错误。

我正面临一个可怕的非结束循环问题,它并没有真正影响我的tkinter窗口本身,但是当关闭它时,在tkinter回调问题中看到这个异常是一种耻辱。

实际上我不知道为什么Valider()函数中的batman变量不会结束所有这些循环 有人可以帮我这个吗?

Ps:对不起代码中的法语 感谢

以下是源代码:

    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()

以下是例外:

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 个答案:

答案 0 :(得分:0)

好的,这里有两件事:

1)你的Valider()函数根据你上面的代码不需要参数,所以你可以简单地绑定而不使用lambda

root.bind('<Return>', Valider)

2)当按钮/返回被触发并且你的Valider()被调用时,就我所知传递了对触发事件的引用(至少在wxPython中它以这种方式完成并且短的googling给了我相同的tkinter )。

这意味着您的触发函数(在本例中为Valider())也必须处理该引用。根据这个,您的Valider()定义应如下所示:

def Valider(event=None):

以这种方式定义Valider()会处理对触发该函数的事件的传入引用,但是您可以使用

直接调用该函数。
Valider()

由于事件参数的默认值设置为

希望有所帮助。 格雷茨: - )