2016-10-11 4 views
0

У меня есть рамка Tkinter, которая по существу показывает группу миниатюр, отображаемых в виджетах Label. Мне нужно, чтобы ярлыки создавались динамически, чтобы приспособить разные числа миниатюр для генерации. У меня есть сгенерированный список имен файлов и можно создавать миниатюры по мере необходимости, но когда я пытаюсь связать функцию с каждой из созданных меток, она, кажется, переместилась на последнюю созданную Label/Binding. В результате только конечная метка имеет связанный с ней метод.Метод привязки к динамически созданным меткам

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() 

Вызываемый метод всегда будет одним и тем же, но как определить ярлык, который будет выполняться?

+0

Ваш пример не работает - вы связываете функцию 'self.test()', но у вас есть только 'self.click()'. А что такое 'self.card'? – furas

+0

извините, плохое редактирование с оригинального кода с моей стороны, исправлено сейчас – Kelly

ответ

1

есть по крайней мере три решения

Первое самое простое:. функция передается объект события, содержащий ссылку на виджет:

label = tk.Label(...) 
label.bind("<Button-1>", self.click) 
... 
def click(self, event): 
    print("you clicked:", event.widget) 

Если вы предпочитаете использовать лямбда, вы можете передать саму метку функции:

label = tk.Label(...) 
label.grid(...) 
label.bind("<Button-1>",lambda event, label=label: self.click(label)) 

Другим решением является сохранить ссылку на каждой этикетке в списке, и передать индекс функция:

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]) 
+0

Отлично, спасибо огромное! Лямбда по-прежнему довольно скользкая для меня! – Kelly

+0

@Kelly: Я обновил свой ответ, чтобы показать, как это сделать без лямбды. ИМО, вы должны использовать только лямбда, если вы _need_ используете лямбда, и похоже, что вам не нужно использовать лямбда. –

+0

Очень ценится, я работал с лямбдой, потому что казалось, что мне нужно пропустить виджет в качестве аргумента в привязке к событию, всегда хорошо видеть альтернативные методы работы! – Kelly

0

Когда вы нажимаете метку, тогда tk запускает функцию с event object, которую вы пропускаете с помощью lambda x.

Вам нужно

lambda event:self.click(event, ...) 

, а затем в click вы можете использовать event.widget, чтобы получить щелкнул виджет.

def click(event, ...); 

    print('Widget text:', event.widget['text']) 

Вы имели проблемы с self.thumb в self.click(self.thumb), потому что вы не знаете, как работает lambda в for цикле. (и это очень популярная проблема :))

lambda является "lazy". Он не получает значение из self.thumb при объявлении lambda x: self.click(self.thumb), но при нажатии кнопки (и вы выполняете lambda. Но при нажатии метки затем for цикла завершается и self.thumb сохраняет последнее значение.

Вы должны использовать этот метод получить правильное значение при объявлении lambda

labda event, t=self.thumb: self,clikc(t) 
Смежные вопросы