tkinter 在for循环中创建按钮传递命令参数
- 2024-11-18 08:41:00
- admin 原创
- 12
问题描述:
我正在尝试在for
循环中在 tkinter 中创建按钮。并且在每个循环中将i
计数值作为命令值中的参数传递出去。因此,当从值调用该函数时,command
我可以知道按下了哪个按钮并采取相应的措施。
问题是,假设长度为 3,它将创建 3 个按钮,标题Game 1
从 到Game 3
,但当按下任何一个按钮时,打印的值始终是2
,即最后一次迭代。因此,按钮似乎是作为单独的实体制作的,但i
命令参数中的值似乎都相同。以下是代码:
def createGameURLs(self):
self.button = []
for i in range(3):
self.button.append(Button(self, text='Game '+str(i+1),
command=lambda: self.open_this(i)))
self.button[i].grid(column=4, row=i+1, sticky=W)
def open_this(self, myNum):
print(myNum)
有没有办法让i
每次迭代的当前值都坚持那个特定的按钮?
这个问题可以看作是在循环中创建函数的一个特例。还有lambda 函数闭包捕获了什么?,以获得更技术性的概述。
另请参阅如何在 Tkinter 中向按钮命令传递参数?以了解向按钮回调传递参数的常见问题。
解决方案 1:
将您的 lambda 更改为lambda i=i: self.open_this(i)
。
这看起来似乎很神奇,但实际上就是这样的。当您使用该 lambda 定义函数时,open_this 调用不会在您定义函数时获取变量 i 的值。相反,它会创建一个闭包,这有点像给自己的提示,说“我应该在调用我时查找变量 i 的值”。当然,该函数是在循环结束后调用的,因此那时 i 将始终等于循环中的最后一个值。
使用这个i=i
技巧会让你的函数在定义 lambda 时存储 i 的当前值,而不是等待稍后查找 i 的值。
解决方案 2:
这就是 Python 中闭包的工作方式。我自己也遇到过这个问题。你可以用functools.partial
这个。
for i in range(3):
self.button.append(Button(self, text='Game '+str(i+1), command=partial(self.open_this, i)))
解决方案 3:
只需将按钮范围附加到 lambda 函数中,如下所示:
btn["command"] = lambda btn=btn: click(btn)
其中click(btn)
是传入按钮本身的函数。这将创建从按钮到函数本身的绑定范围。
特征:
自定义网格大小
响应式调整大小
切换活动状态
#Python2
#from Tkinter import *
#import Tkinter as tkinter
#Python3
from tkinter import *
import tkinter
root = Tk()
frame=Frame(root)
Grid.rowconfigure(root, 0, weight=1)
Grid.columnconfigure(root, 0, weight=1)
frame.grid(row=0, column=0, sticky=N+S+E+W)
grid=Frame(frame)
grid.grid(sticky=N+S+E+W, column=0, row=7, columnspan=2)
Grid.rowconfigure(frame, 7, weight=1)
Grid.columnconfigure(frame, 0, weight=1)
active="red"
default_color="white"
def main(height=5,width=5):
for x in range(width):
for y in range(height):
btn = tkinter.Button(frame, bg=default_color)
btn.grid(column=x, row=y, sticky=N+S+E+W)
btn["command"] = lambda btn=btn: click(btn)
for x in range(width):
Grid.columnconfigure(frame, x, weight=1)
for y in range(height):
Grid.rowconfigure(frame, y, weight=1)
return frame
def click(button):
if(button["bg"] == active):
button["bg"] = default_color
else:
button["bg"] = active
w= main(10,10)
tkinter.mainloop()
解决方案 4:
这是因为名称的值i
发生了变化,并且未被捕获。(您可以通过在循环后lambda:
添加并观察会发生什么来尝试该理论。)i = 1234
您需要编写一个函数将其包装i
为本地名称,然后在该函数中返回捕获的 lambda i
。
def make_button_click_command(i):
return lambda: button_click(i)
# ...
btn = Button(..., command=make_button_click_command(i))
另一个选项是functools.partial
,它实际上可以完成相同的事情:
command=functools.partial(button_click, i)
总而言之,您还可以通过仅使用range
从 0 到 10 的数字并divmod
在一个函数调用中获取行和列来简化一些事情:
from tkinter import Tk, Button
def button_click(i):
print(i)
def make_button_click_command(i):
return lambda: button_click(i)
root = Tk()
for i in range(10):
value = (i + 1) % 10
row, col = divmod(i, 3)
btn = Button(root, text=value, padx=40, pady=20, command=make_button_click_command(value))
btn.grid(row=row + 1, column=col)
root.mainloop()
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件