How can I create button callbacks correctly with Tkinter?
Here I have a simple python application using Tkinter
from Tkinter import *
def draw(i,j):
button[(i,j)]['text'] = 'X'
if __name__ == '__main__':
root = Tk()
root.title('Number Recognation')
button = {}
for i in range(2):
for j in range(2):
button[(i,j)] = Button(width = 3,command = lambda: draw(i,j))
button[(i,j)].grid(row = i,column = j)
root.mainloop()
I want to make a small program where there are four empty buttons, and where you click one of them, it changes the text to "X". Therefore, when I write this program using loops for
, it does not work correctly, when clicked, it changes this button, which is in the second row and in the second column. If I write without for
loops
button[(0,0)] = Button(width = 3,command = lambda: draw(0,0))
button[(0,0)].grid(row = 0,column = 0)
button[(0,1)] = Button(width = 3,command = lambda: draw(0,1))
button[(0,1)].grid(row = 0,column = 1)
button[(1,0)] = Button(width = 3,command = lambda: draw(1,0))
button[(1,0)].grid(row = 1,column = 0)
button[(1,1)] = Button(width = 3,command = lambda: draw(1,1))
button[(1,1)].grid(row = 1,column = 1)
no problem here.
Indeed, I want to use for a loop because I will have a lot of buttons here.
source to share
i
, is j
bound when the callback is invoked, not when the callback is created. You can use the default setting to avoid the late binding problem.
for i in range(2):
for j in range(2):
button[(i,j)] = Button(width = 3,command = lambda i=i, j=j: draw(i,j)) # <---
button[(i,j)].grid(row = i,column = j)
source to share