Reputation: 57
I have a Tkinter frame that is essentially showing a group of thumbnails, displayed in Label widgets. I need the Labels to be created dynamically to accommodate differing numbers of thumbnails to generate. I have a generated list of file names, and can create the thumbnails as needed, but when I try to bind a function to each of the created labels, it seems to be over ridden by the last created Label/Binding. The result is that only the final label has the method bound to it.
import tkinter as tk
class test(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args)
self.shell = tk.Frame(self)
self.shell.pack()
self.create_widgets()
def create_widgets(self):
'''
Two rows of labels
'''
for row in range(2):
for i in range(5):
text = 'Thumbnail\nrow{}\ncolumn{}'.format(row,i)
self.thumb = tk.Label(self.shell,
text = text)
self.thumb.grid(row = row, column = i, sticky = 'news')
self.thumb.bind("<Button-1>",lambda x: self.click(self.thumb))
def click(self, *args):
#This should affect only the Label that was clicked
print('CLICK!')
app = test()
root = app
root.mainloop()
The method being called will always be the same, but how do I identify the Label to be effected?
Upvotes: 0
Views: 2092
Reputation: 386020
There are at least three solutions.
The first is the simplest: the function is passed an event object that contains a reference to the widget:
label = tk.Label(...)
label.bind("<Button-1>", self.click)
...
def click(self, event):
print("you clicked:", event.widget)
If you prefer to use lambda, you can pass the label itself to the function:
label = tk.Label(...)
label.grid(...)
label.bind("<Button-1>",lambda event, label=label: self.click(label))
Another solution is to keep a reference to every label in a list, and pass the index to the function:
self.labels = []
for row in range(2):
for i in range(5):
label = tk.Label(...)
label.grid(...)
self.labels.append(label)
index = len(self.labels)
label.bind("<Button-1>",lambda event, i=index: self.click(i))
...
def click(self, index):
print("the label is ", self.labels[index])
Upvotes: 2
Reputation: 142681
When you click label then tk runs function with event object
which you skip using lambda x
.
You need
lambda event:self.click(event, ...)
and then in click
you can use event.widget
to get clicked widget.
def click(event, ...);
print('Widget text:', event.widget['text'])
You had problem with self.thumb
in self.click(self.thumb)
because you don't know how works lambda
in for
loop. (and it is very popular problem :) )
lambda
is "lazy"
. It doesn't get value from self.thumb
when you declare lambda x: self.click(self.thumb)
but when you click button (and you execute lambda
. But when you click label then for
loop is finished and self.thumb
keeps last value.
You have to use this method to get correct value when you declare lambda
labda event, t=self.thumb: self,clikc(t)
Upvotes: 0