2010-10-18 1 views
2

Я писал длинный графический интерфейс в Python, используя Tkinter. Одна вещь, которую я не понимаю, - это то, почему я не могу привязывать события к виджетам в цикле. В приведенном ниже коде привязка работает хорошо, если я делаю это вручную (закомментировал код), но не в цикле for. Я делаю что-то неправильно?Неожиданное поведение Tkinter

импорта Tkinter

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

Было бы хорошо, если вы можете добавить ошибку, которая производится. – pyfunc

+0

Не может ли это быть связано с тем, что вы не используете '' "' в своем цикле? – nmichaels

+0

@pyfunc Когда я нажимаю стрелку вниз, например, я получаю эту ошибку. Исключение в обратном вызове Tkinter Traceback (последний последний вызов): Файл «/usr/lib/python2.6/lib-tk/Tkinter.py», строка 1413, в __call__ return self.func (* args) Файл «events.py», строка 17, в Кнопки [i] .bind («», лямбда x: кнопки [i + 1] .focus_set()) IndexError: индекс индекса за пределами допустимого диапазона – Thea

ответ

3

Ваши затворы (лямбды) не работают, как вы ожидаете их. Они содержат ссылки на i, которые мутируются по мере повторения цикла, и в конце все лямбды из одного и того же цикла ссылаются на одну и ту же последнюю последнюю кнопку.

Вот пример поведения:

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

Nice иллюстрации –

+0

Хм .... я вижу. Мне нужно время, чтобы лучше изучить лямбда. Спасибо за вашу помощь. – Thea

+0

Это не о лямбдах, а о закрытии. Вы можете определить функцию с 'def' вместо лямбда в цикле, и результат будет таким же. –

3

Вы можете решить эту проблему с:

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

Обратите внимание на i=i аргумент к lambda закрытия.

+0

Спасибо большое! Это решило проблему! – Thea