Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I construct button callbacks with Tkinter properly?

Here I have a simple python app 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 little program where are four blank buttons and where you push one of them, it changes it's text to "X". So when I write this program using of for loops, it is not working correctly, on click it changes this button which stands in the second row and 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)

here is not a problem.

Really I want to use for loop, because I am going to have many buttons here.

like image 926
godot Avatar asked Feb 28 '26 00:02

godot


1 Answers

i, j is bound when the callback is called, not when the callback is created. You can use default parameter 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)
like image 106
falsetru Avatar answered Mar 02 '26 12:03

falsetru



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!