I'm trying to create a column of label containing images in a for loop, I want them to have a specific command when I do a right click a left click on the image, I searched a solution and found this question. The answer of BrenBarn worked well only if i use a button. But the event Button-1, isn't returning any value that can differentiate one label from another.
WORKING :
active="red"
default_color="white"
def main(height=5,width=5):
for x in range(width):
for y in range(height):
btn = tkinter.Button(frame, bg=default_color)
btn.grid(column=x, row=y, sticky=N S E W)
btn["command"] = lambda btn=btn: click(btn)
for x in range(width):
Grid.columnconfigure(frame, x, weight=1)
for y in range(height):
Grid.rowconfigure(frame, y, weight=1)
return frame
def click(button):
print(button)
if(button["bg"] == active):
button["bg"] = default_color
else:
button["bg"] = active
w= main(10,10)
NOT WORKING :
active="red"
default_color="white"
def main(height=5,width=5):
for x in range(width):
for y in range(height):
btn = tkinter.Button(frame, bg=default_color)
btn.grid(column=x, row=y, sticky=N S E W)
btn.bind("<Button-1>", lambda btn=btn: click(btn))
for x in range(width):
Grid.columnconfigure(frame, x, weight=1)
for y in range(height):
Grid.rowconfigure(frame, y, weight=1)
return frame
def click(button):
print(button)
if(button["bg"] == active):
button["bg"] = default_color
else:
button["bg"] = active
w= main(10,10)
CodePudding user response:
Consider this line of code:
btn.bind("<Button-1>", lambda btn=btn: click(btn))
You're creating an anonymous function that takes a single argument. You call this argument btn
. When tkinter calls the function via a binding it automatically calls the function with one argument representing the event. So, when the function is called because of the <Button-1>
event, btn
is set to the event object, overriding the default value.
You need to define your lambda
function to accept this event parameter in addition to any other arguments. One way to do it is like this:
btn.bind("<Button-1>", lambda event, btn=btn: click(btn))
With this, the lambda
function receives the event parameter and also defines a default value for btn
which is then passed to the click
function.
However, if you're using bind
rather than setting the command
attribute of the button, there's no need to pass in the button itself. The widget is one of the attributes of the event object.
You can redefine your function to accept the event and use the widget
parameter like so:
def click(event):
button = event.widget
print("Button:", button)
if(button["bg"] == active):
button["bg"] = default_color
else:
button["bg"] = active
You would then define the button like so:
btn.bind("<Button-1>", click)