Python tkinter为循环传递命令参数创建按钮
我正在尝试在for循环中的tkinter中创建按钮。在每个循环中,将i count值作为参数传递给命令值。因此,当从命令值调用函数时,我可以知道按下了哪个按钮,并相应地执行操作。问题是,假设len为3,它将创建3个标题为“Game 1”到“Game 3”的按钮,但当按下任何按钮时,打印值始终为2,即最后一次迭代。因此,按钮似乎是作为单独的实体制作的,但命令参数中的i值似乎完全相同。代码如下:Python tkinter为循环传递命令参数创建按钮,python,tkinter,Python,Tkinter,我正在尝试在for循环中的tkinter中创建按钮。在每个循环中,将i count值作为参数传递给命令值。因此,当从命令值调用函数时,我可以知道按下了哪个按钮,并相应地执行操作。问题是,假设len为3,它将创建3个标题为“Game 1”到“Game 3”的按钮,但当按下任何按钮时,打印值始终为2,即最后一次迭代。因此,按钮似乎是作为单独的实体制作的,但命令参数中的i值似乎完全相同。代码如下: def createGameURLs(self): self.button = [] f
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值,以使用特定的按钮?这就是闭包在python中的工作方式。我自己也遇到过这个问题。 你可以用这个
for i in range(3):
self.button.append(Button(self, text='Game '+str(i+1), command=partial(self.open_this, i)))
将lambda更改为
lambda i=i:self。打开此(i)
这可能看起来很神奇,但发生的事情如下。使用该lambda定义函数时,此调用的open_在定义函数时不会获取变量i的值。取而代之的是,它做了一个闭包,这有点像是给自己写了一个便条,上面写着“我应该寻找我被调用时变量I的值”。当然,这个函数是在循环结束后调用的,所以在那个时候,我将始终等于循环中的最后一个值
使用
i=i
技巧可使函数在定义lambda时存储i的当前值,而不是等待以后查找i的值。只需将按钮范围附加到lambda函数中,如下所示:
btn[“command”]=lambda btn=btn:click(btn)
其中click(btn)
是按钮本身传递的功能。
这将创建一个从按钮到函数本身的绑定范围
特点:
- 自定义网格大小
- 响应式调整尺寸
- 切换活动状态
非常感谢你们两位,卢卡德和布伦巴恩,我已经为此奋斗了好几天,信不信由你。两种方法都非常有效。我暂时使用了I=I修复程序,但我肯定会仔细阅读这些工具。我很欣赏这两个答案。如果BrenBarns的解决方案对您有效,那么您应该将其标记为您接受的答案。如果我们想将两个参数传递给像open_this这样的函数,可能会出现重复?阿门:这取决于您希望这些参数是什么。如果两者都来自某个外部循环,并且您希望以上面所示的方式“冻结”它们,那么您只需执行
lambda x=x,y=y:self。打开这个(x,y)
。这是一个出色、直截了当且很好的解释。这应该是答案。@BrenBarn刚才我遇到了同样的情况,真是太神奇了。我真的很奇怪你们是怎么发现这些技术的。“太谢谢你了!”酷云:跟我说的一样。您说过“参数存储在函数中”。我说“函数存储值”。这是同样的事情。看起来很简单,如果你使用虚拟环境,你可能会遇到问题,请参阅第一页:self.button.append(button(self,text='Game'+str(i+1),command=lambda x=i:self.open_this(x))
#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()