views:

28

answers:

2

Hi everyone,

I've been writing a long GUI in Python using Tkinter. One thing that I don't understand is why I can't bind events to widgets in a loop. In the code below, binding works well if I do it manually (commented out code) but not in a for loop. Am I doing something wrong?

import 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()
+3  A: 

Your closures (lambdas) are not working as you expect them to. They keep references to i which is mutated as the loop iterates, and in the end all lambdas from the same loop refer to the same single last button.

Here's an illustration of the behaviour:

>>> k = []
>>> for i in range(5):
...     k.append(lambda: i)
>>> k[0]()
4
>>> [f() for f in k]
[4, 4, 4, 4, 4]
Gintautas Miliauskas
Nice illustration
Bryan Oakley
Hmm.... I see. I need some time to study lambdas better. Thanks for your help.
Thea
It's not really about lambdas, but about closures. You could define a function with `def` instead of a lambda in the loop, and the result would be the same.
Gintautas Miliauskas
+2  A: 

You can fix the problem with:

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

Note the i=i argument to the lambda closure.

ars
Thanks a lot! That solved the problem!
Thea