本文介绍了Tkinter 回调异常,因为循环在后台继续的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,论坛里的人,

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

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.

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

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.

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

Actually I don't know why my batman variable in Valider() function doesn't end all these loopsCan someone help me with this one ?

Ps:抱歉代码中的法语谢谢

Ps: sorry for French language in the codeThanks

这是源代码:

    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) 根据上面的代码,您的 Valider() 函数不需要任何参数,因此您可以简单地绑定而不使用 lambda

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) 当按钮/返回被触发并且你的 Valider() 被调用时,一个对触发事件的引用被传递,据我所知(至少在 wxPython 中它是这样完成的,并且简短的谷歌搜索给了我同样的 tkinter).

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

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

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

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

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

因为 event 参数的默认值设置为 None

as the event parameter has a default value set as None

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

Hope that helps.Greetz :-)

这篇关于Tkinter 回调异常,因为循环在后台继续的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-26 15:24