Динамически генерировать кнопки Tkinter - PullRequest
3 голосов
/ 21 ноября 2010

Я хочу сгенерировать количество кнопок Tkinter, которые делают разные вещи.У меня есть этот код:

import Tkinter as tk

for i in range(boardWidth):
    newButton = tk.Button(root, text=str(i+1), 
        command=lambda: Board.playColumn(i+1, Board.getCurrentPlayer()))
    Board.boardButtons.append(newButton)

Если boardWidth равен 5, хотя я получаю кнопки с меткой 1-5, при нажатии они все делают Board.playColumn (5, Board.getCurrentPlayer ()).

Мне нужна первая кнопка для выполнения Board.playColumn (1, Board.getCurrentPlayer ()), вторая для выполнения Board.playColumn (2, Board.getCurrentPlayer ()) и т. Д.

Спасибо залюбая помощь!

Ответы [ 2 ]

11 голосов
/ 21 ноября 2010

Мне кажется, проблема в том, что lambda получает окончательное значение i после окончания цикла for. Это должно исправить это (не проверено):

import Tkinter as tk

for i in range(boardWidth):
    newButton = tk.Button(root, text=str(i+1),
        command=lambda j=i+1: Board.playColumn(j, Board.getCurrentPlayer()))
    Board.boardButtons.append(newButton)

Обновление

Кстати, это работало путем добавления аргумента к функции lambda со значением по умолчанию, рассчитанным из значения i в момент создания каждого в цикле, а не со ссылкой на окончательное значение i через замыкание, когда выражение внутри него выполняется позже.

2 голосов
/ 21 ноября 2010

Ваша проблема в том, что вы создаете множество lambda объектов в одном и том же пространстве имен, и эти lambda ссылаются на имена во внешней области видимости.Это означает, что они не становятся замыканиями и не хранят ссылки на объекты до тех пор, пока позже ... Когда это произойдет, все лямбды будут ссылаться на последнее значение i.

Попробуйте использовать обратный вызовЧтобы исправить это:

import Tkinter as tk

def callbackFactory(b, n):
    def _callback():
        return b.playColumn(n, b.getCurrentPlayer())
    return _callback

for i in range(boardWidth):
    newButton = tk.Button(root, text=str(i+1), 
        command=callbackFactory(Board, i+1))
    Board.boardButtons.append(newButton)

Другая идея заключается в том, чтобы сохранить текущее значение i как значение аргумента по умолчанию в объекте lambda, вместо того чтобы полагаться на поведение замыкания для хранения ссылки:

for i in range(boardWidth):
    newButton = tk.Button(root, text=str(i+1), 
        command=lambda x=i: Board.playColumn(x+1, Board.getCurrentPlayer()))
    Board.boardButtons.append(newButton)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...