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()
Your closures (lambdas) are not working as you expect them to. They keep references to
iwhich 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: