2010-10-18 9 views
2

J'ai écrit une longue interface graphique en Python en utilisant Tkinter. Une chose que je ne comprends pas est pourquoi je ne peux pas lier les événements aux widgets dans une boucle. Dans le code ci-dessous, la liaison fonctionne bien si je le fais manuellement (code commenté) mais pas dans une boucle for. Est-ce que je fais quelque chose de mal?Tkinter comportement inattendu

Tkinter import

root = Tkinter.Tk() 

b1 = Tkinter.Button(root, text="Button 1") 
b1.pack() 
b1.focus_set() 
b2 = Tkinter.Button(root, text="Button 2") 
b2.pack() 
b3 = Tkinter.Button(root, text="Button 3") 
b3.pack() 


def up_and_down(*buttons): 

    for i in range(len(buttons)-1): 
    buttons[i].bind("<Down>", lambda x: buttons[i+1].focus_set()) 

    for i in range(1, len(buttons)): 
    buttons[i].bind("<Down>", lambda x: buttons[i-1].focus_set()) 

    ''' 
    buttons[0].bind("<Down>", lambda x: buttons[1].focus_set()) 
    buttons[1].bind("<Down>", lambda x: buttons[2].focus_set()) 

    buttons[1].bind("<Up>", lambda x: buttons[0].focus_set()) 
    buttons[2].bind("<Up>", lambda x: buttons[1].focus_set()) 
    ''' 

up_and_down(b1, b2, b3) 

root.mainloop() 
+0

Ce serait bien, si vous pouvez ajouter l'erreur qui est produite. – pyfunc

+0

Cela peut-il être lié au fait que vous n'utilisez pas "" dans votre boucle? – nmichaels

+0

@pyfunc Lorsque j'appuie sur la flèche vers le bas par exemple, j'obtiens cette erreur. Exception dans le rappel Tkinter Traceback (appel le plus récent en dernier): Fichier "/usr/lib/python2.6/lib-tk/Tkinter.py", ligne 1413, dans __call__ return self.func (* args) Fichier "events.py", ligne 17, dans boutons [i] .bind ("", lambda x: boutons [i + 1] .focus_set()) IndexError: index de tuple hors plage – Thea

Répondre

3

Vos fermetures (lambdas) ne fonctionnent pas comme vous attendre à ce qu'ils. Ils gardent des références à i qui est muté lorsque la boucle itère, et à la fin tous les lambdas de la même boucle se réfèrent au même dernier bouton unique.

est ici une illustration du comportement:

>>> k = [] 
>>> for i in range(5): 
...  k.append(lambda: i) 
>>> k[0]() 
4 
>>> [f() for f in k] 
[4, 4, 4, 4, 4] 
+0

Belle illustration –

+0

Hmm .... Je vois. J'ai besoin de temps pour mieux étudier les lambdas. Merci de votre aide. – Thea

+0

Il ne s'agit pas vraiment de lambdas, mais de fermetures. Vous pouvez définir une fonction avec 'def' au lieu d'un lambda dans la boucle, et le résultat sera le même. –

3

Vous pouvez résoudre le problème avec:

for i in range(len(buttons)-1): 
    buttons[i].bind("<Down>", lambda x, i=i: buttons[i+1].focus_set()) 

for i in range(1, len(buttons)): 
    buttons[i].bind("<Down>", lambda x, i=i: buttons[i-1].focus_set()) 

Notez le argument i=i à la fermeture lambda.

+0

Merci beaucoup! Cela a résolu le problème! – Thea

Questions connexes