tkinter button commands with lambda in Python

23,454

Solution 1

You can fix this problem by creating a closure for i and j with the creation of each lambda:

command = lambda i=i, j=j: update_binary_text(i, j)

You could also create a callback factory with references to the button objects themselves:

def callback_factory(button):
    return lambda: button["text"] = "1"

And then in your initialization code:

for j in range(0, number):
    new_button = Button(root, text=" ")
    new_button.configure(command=callback_factory(new_button))
    new_button.pack()
    buttonList.append(new_button)

Solution 2

Whenever I need a collection of similar widgets, I find it's simplest to enclose them in an object and pass a bound-method as callback rather than playing tricks with lambda. So, instead of having a list like buttonList[] with widgets, create an object:

class MyButton(object):
    def __init__(self, i, j):
        self.i = i
        self.j = j
        self.button = Button(..., command = self.callback)

    def callback(self):
        . . .

Now, you have a list buttonList[] of these objects, rather than the widgets themselves. To update the text, either provide a method for that, or else access the member directly: buttonList[i].button.configure(. . .) And when the callback is activated, it has the entire object and whatever attributes you might need in self.

Share:
23,454
vap
Author by

vap

Updated on July 09, 2022

Comments

  • vap
    vap almost 2 years

    ive tried searching for a solution but couldn't find one that works. I have a 2d list of tkinter Buttons, and i want to change their Text when it is clicked by the mouse. I tried doing this:

    def create_board(number):
        print(number)
        for i in range (0,number):
            buttonList.append([])
            for j in range(0,number):
                print(i,j)
                buttonList[i].append(Button(root, text = " ", command = lambda: update_binary_text(i,j)))
                buttonList[i][j].pack()
    

    Then when it is clicked it calls this function:

    def update_binary_text(first,second):
        print(first,second)
        buttonList[first][second]["text"] = "1"
    

    When i click a button, it simply does nothing, i had the program display the indexes of the button that was clicked, and they ALL show 4, 4 (this is when the variable number=5) Is there an solution to this?
    this is my first python attempt for a class.

    Thanks

  • vap
    vap about 11 years
    WOW! your solution worked! thank you sir! For now i stuck with the first example you posted. But i will definitely study the second example you showed as well. Thanks again!