Home > Software engineering >  create labels in a for loop that have an individual commande
create labels in a for loop that have an individual commande

Time:07-05

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)
  • Related