Neo630
Neo630

Reputation: 191

How to print text in labels created from a list when clicked on

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

Answers (1)

Mike - SMT
Mike - SMT

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

Related Questions