how to give different command to buttons created in a loop in tkinter?

Question:

I am trying to create multiple buttons on a loop,
something like:

def press_button(button):
    button.configure(bg="red")


root = tkinter.Tk()

for i in range(4):
    quick_button = tkinter.Button(root, text=str(i) ,font=("courier", 30), 
                                  command=lambda: press_button(quick_button))
    quick_button.grid(row=i, pady=3, padx=3)

root.mainloop()

but I want each button to send different argument, what I want is that each button will send different argument, but what happened is that they all set to the same thing, so when I press the first button, the three buttons are being colored.
Also, is there a way to reference buttons without putting them in a dictionary when creating them?

Any help will be appreciated

Asked By: elii236

||

Answers:

Lambdas don’t immediately bind the values they use. They are closures and look up the values needed when invoked. What this means is that it will only act on the last quick_button since that is what quick_button equals after your loop is finished. On top of that, you are trying to reference quick_button before it exists!

What if I told you that you could exploit this late binding behavior which is causing your problem to actually help solve your problem?

We can store a list of your buttons (buttons) and store the index of the button as a local variable within your lambda. You will then use that index to access the button that was pressed and pass that to your press_button function.

It would look something like this:

import tkinter

def press_button(button):
    button.configure(bg="red")


root = tkinter.Tk()

buttons = [] # <-- Added list of buttons
for i in range(4):
    quick_button = tkinter.Button(root, text=str(i) ,font=("courier", 30), 
                                  command=lambda i=i: press_button(buttons[i]))
    quick_button.grid(row=i, pady=3, padx=3)
    buttons.append(quick_button)

root.mainloop()

Notice the lambda i=i part. Without the i=i, you would experience the same behavior as you are experiencing now… When the lambda is called, it will look up the value of i and see that it’s 3 no matter what button you press. Adding the i=i to the lambda binds it locally within the lambda.

Now, each button behaves “independently” from the rest:

red buttons

Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.