动态生成 Tkinter 按钮
Posted
技术标签:
【中文标题】动态生成 Tkinter 按钮【英文标题】:Generate Tkinter Buttons dynamically 【发布时间】:2011-05-13 06:42:16 【问题描述】:我想生成 n
数量的 Tkinter Button
s 来做不同的事情。我有这个代码:
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())
,依此类推。
【问题讨论】:
【参考方案1】:您的问题是您在同一个命名空间中创建了许多 lambda
对象,而这些 lambda
s 引用了外部范围内的名称。这意味着它们不会成为闭包,并且它们不会存储对对象的引用,直到以后......当它发生时,所有 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)
【讨论】:
按照 martineau 的建议尝试了第二个示例。感谢您解释为什么会发生这种情况!【参考方案2】:我认为问题在于lambda
在for
循环结束后获取i
的最终值。这应该可以解决这个问题(未经测试):
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
的值计算得出的,而不是引用@987654327 的最终值@ 在其中的表达式稍后执行时通过闭包。
【讨论】:
以上是关于动态生成 Tkinter 按钮的主要内容,如果未能解决你的问题,请参考以下文章