42

我正在尝试在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每次迭代中获取当前值以坚持那个特定的按钮?

4

3 回答 3

109

将您的 lambda 更改为lambda i=i: self.open_this(i).

这可能看起来很神奇,但这就是正在发生的事情。当您使用该 lambda 定义函数时, open_this 调用不会在您定义函数时获取变量 i 的值。相反,它创建了一个闭包,这有点像给自己的一个注释,说“我应该在我被调用时查找变量 i 的值”。当然,该函数是在循环结束后调用的,所以那时 i 将始终等于循环中的最后一个值。

使用该i=i技巧会使您的函数在定义 lambda 时存储 i 的当前值,而不是等待稍后查找 i 的值。

于 2012-06-02T19:15:21.677 回答
8

这就是闭包在 python 中的工作方式。我自己曾经遇到过这个问题。你可以用functools.partial这个。

for i in range(3):
    self.button.append(Button(self, text='Game '+str(i+1), command=partial(self.open_this, i)))
于 2012-06-02T19:13:41.307 回答
1

只需将您的按钮范围附加到 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()

在此处输入图像描述 在此处输入图像描述

在此处输入图像描述

于 2020-01-29T09:55:16.843 回答