2016-12-06 2 views
0

Это в tkinter. В последней строке добавляется x = len (FRAME_LIST) «Кнопки» в раскрывающемся меню. Проблема в том, что все они ссылаются на один и тот же фрейм (последний в FRAME_LIST). Как я могу сделать так, чтобы каждая кнопка ссылалась на другой кадр из FRAME_LIST?Как сделать кнопки с петлей

for F in FRAME_LIST: 
     frame = ChallengePage(mainframe,self, F) 
     self.frames[F] = frame 
     frame.grid(row = 0, column = 0, sticky = "nsew") 
     subMenu1.add_command(label = F.id, command = lambda: self.show_frames(F)) 

EDIT: Так, чтобы быть более точным, когда я наткнулся на эту проблему я думал, хорошо, проблема в том, мне нужно объявить локальную переменную, так что я попытался это:

 A = F 
     subMenu1.add_command(label = F.id, command = lambda: self.show_frames(A)) 

Но он не работал, хотя A объявлен INSIDE в цикле и обновлен в каждом цикле, он все равно дает тот же результат.

Я пришел прямо сейчас по ссылке: https://docs.python.org/3/faq/programming.html#why-do-lambdas-defined-in-a-loop-with-different-values-all-return-the-same-result

, где он показывает решение:

 subMenu1.add_command(label = F.id, command = lambda A = F: self.show_frames(A)) 

Что-то магическим образом работает, но я не понимаю, почему это любая diffrent из моего местного А.

ответ

0

Это обычная проблема при использовании lambda в цикле. Я обычно использую partial вместо:

from functools import partial 

for F in FRAME_LIST: 
    frame = ChallengePage(mainframe, self, F) 
    self.frames[F] = frame 
    frame.grid(row=0, column=0, sticky="nsew") 
    subMenu1.add_command(label=F.id, command=partial(self.show_frames, F)) 

Потому что: closures.

Подведем итог: lambda в цикле будет помнить имя переменной (F), но не значение он указывает на каждой итерации цикла. К тому времени, когда вы нажимаете кнопки и запускаете команду, имя F указывает на последнее значение в итерации вашего цикла for, и именно это будет передано вашей лямбда. Partials, с другой стороны, знают об объекте, который F указывает на каждую итерацию и отслеживает его так, что self.show_frames() вызывается с соответствующим аргументом.

Смежные вопросы