Reputation: 191
I am creating labels from a list by looping through the list and creating each label as the for loop iterates through the list. I am trying to get the program to print the text in the label when it is clicked on, but instead, the program is printing the name of the last label created.
Code
from tkinter import *
from tkinter import ttk
root = Tk()
friends = ["Luke", "Justin", "Sam"]
# *** Scrollable Frame Class ***
class VerticalScrolledFrame(Frame):
def __init__(self, parent, *args, **kw):
Frame.__init__(self, parent, *args, **kw)
vscrollbar = Scrollbar(self, orient=VERTICAL)
vscrollbar.pack(fill=Y, side=LEFT, expand=FALSE)
canvas = Canvas(self, bd=0, highlightthickness=0, yscrollcommand=vscrollbar.set, bg="#383C41")
canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
vscrollbar.config(command=canvas.yview)
canvas.xview_moveto(0)
canvas.yview_moveto(0)
self.interior = interior = Frame(canvas)
interior_id = canvas.create_window(0, 0, window=interior,
anchor=NW)
def _on_mousewheel(event):
canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
self.interior.bind_all("<MouseWheel>", _on_mousewheel)
canvas.bind_all("<MouseWheel>", _on_mousewheel)
def _configure_interior(event):
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
canvas.config(scrollregion="0 0 %s %s" % size)
if interior.winfo_reqwidth() != canvas.winfo_width():
canvas.config(width=interior.winfo_reqwidth())
interior.bind('<Configure>', _configure_interior)
def _configure_canvas(event):
if interior.winfo_reqwidth() != canvas.winfo_width():
canvas.itemconfigure(interior_id, width=canvas.winfo_width())
canvas.bind('<Configure>', _configure_canvas)
def switch_target(event):
print(name.cget("text"))
# *** Set frame for friends view ***
friends_frame = VerticalScrolledFrame(root, bg="#23272A")
friends_frame.pack(side=LEFT, fill=BOTH, expand=TRUE)
for friend in friends:
friend_frame = Frame(friends_frame.interior)
friend_frame.pack(fill=X)
name = Label(friend_frame, text=friend, bg="#45494D", fg="white")
name.pack(side=TOP, fill=X)
name.bind("<Button-1>", switch_target)
root.mainloop()
Examples:
If I click on the label "Luke", the output is Sam
The output should be the same as the label I click on, if I click on "Luke", it should print Luke
Any help would be greatly appreciated!
Upvotes: 0
Views: 146
Reputation: 15226
You need to change 2 things.
One you need to add a lambda function in order to keep the bind associated with the correct widget.
Two you need to update your print statement.
Try this:
def switch_target(widget):
print(widget['text'])
# *** Set frame for friends view ***
friends_frame = VerticalScrolledFrame(root, bg="#23272A")
friends_frame.pack(side=LEFT, fill=BOTH, expand=TRUE)
for friend in friends:
friend_frame = Frame(friends_frame.interior)
friend_frame.pack(fill=X)
name = Label(friend_frame, text=friend, bg="#45494D", fg="white")
name.pack(side=TOP, fill=X)
name.bind("<Button-1>", lambda e, n=name: switch_target(n))
root.mainloop()
Your main problem is that in your loop you are redefining what name
is ever loop until finally your last loop. So it will only ever be your last value.
This is where lambdas come in to help. They allow us to store the value as it is at the moment of each loop keeping the value or reference correct.
Upvotes: 2