动态生成Tkinter按钮

时间:2010-11-21 02:51:25

标签: python user-interface button tkinter

我想生成n个不同的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 个答案:

答案 0 :(得分:11)

我认为问题是lambdai循环结束后正在获取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)

<强>更新

BTW,这是通过在lambda函数中添加一个参数来实现的,该参数的默认值是在循环中创建每个函数时从i的值计算的,而不是返回到最终i在其中的表达式稍后执行时通过闭包的值。

答案 1 :(得分:2)

您的问题是您在同一名称空间中创建了大量lambda个对象,而lambda个引用了外部作用域中的名称。这意味着它们不会成为闭包,并且它们不会存储对象的引用,直到以后......当它发生时,所有lambdas都将引用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)