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.

+3


source to share


1 answer


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)

      

+3


source







All Articles