[英]How do you use the same function as the command for multiple buttons created in a loop?
I am creating a tic-tac-toe board of buttons. 我正在创建一个井字游戏板按钮。 Each button, when clicked, should switch to an X or an O on an alternating basis. 单击每个按钮时,应交替切换为X或O。 I have created the buttons inside for loops, and would, if possible, like to avoid initializing them each separately. 我已经在for循环中创建了按钮,并且在可能的情况下希望避免分别单独初始化它们。 I have tried passing the button to the function by using lambda, and I have tried eliminating the problem of parameters in commands by calling the buttons self.bttn (as this is all taking place within my modified Frame class). 我尝试使用lambda将按钮传递给函数,并且尝试通过调用按钮self.bttn消除命令中的参数问题(因为这全部发生在修改后的Frame类中)。 However, in both cases, I come across the problem that, regardless of which of the 9 buttons I click on, the final button created by the for loops responds. 但是,在这两种情况下,我都遇到了一个问题,即无论我单击9个按钮中的哪个按钮,for循环创建的最终按钮都会响应。
def __build_board(self):
""" Creates tic-tac-toe board of 9 blank buttons. """
for row_num in range(3):
for col_num in range(3):
self.bttn = Button(self, text = " ", command = self.__change_button)
self.bttn.grid(row = row_num + 1, column = col_num, sticky = W)
That's the way that I tried it with self.bttn. 这就是我用self.bttn尝试的方式。 self.__change_button merely switches the text within self.bttn to an X or O. And this is the way I tried it with lambda... self .__ change_button只是将self.bttn中的文本切换为X或O。这就是我使用lambda尝试的方式...
def __build_board(self):
""" Creates tic-tac-toe board of 9 blank buttons. """
for row_num in range(3):
for col_num in range(3):
bttn = Button(self, text = " ", command = lambda: self.__change_button(bttn))
bttn.grid(row = row_num + 1, column = col_num, sticky = W)
I think I understand why these ways of going about it do not work. 我想我理解为什么这些解决方法不起作用。 Seemingly, I have commanded all the buttons to change the text of the final button, but I'm at a loss as to how I should get them to each change their own text the way I want. 看来,我已命令所有按钮更改最终按钮的文本,但是我对如何让它们按自己想要的方式更改自己的文本感到困惑。 Any help would be greatly appreciated. 任何帮助将不胜感激。
This is a tricky problem... 这是一个棘手的问题...
the reason is that the lambda
will be tied to the bttn
variable , not to its value and therefore all the buttons will act on the last button (because that will be the value of the variable after the loop). 原因是lambda
将绑定到bttn
变量 ,而不是其值,因此所有按钮将作用于最后一个按钮(因为这将是循环后变量的值)。
To see this consider: 看到这个考虑:
x = 1
y = lambda : x
print(y()) # will print 1
x = 2
print(y()) # will print 2; lambda captures variables, not values
A possible work-around is: 可能的解决方法是:
def __build_board(self):
""" Creates tic-tac-toe board of 9 blank buttons. """
for row_num in range(3):
for col_num in range(3):
def mkbutton():
b = Button(self, text = " ",
command = lambda: self.__change_button(b))
return b
bttn = mkbutton()
bttn.grid(row = row_num + 1, column = col_num, sticky = W)
this way each lambda
will be tied to its own separate variable b
. 这样,每个lambda
都将绑定到其自己的单独变量b
。
Normally this kind of issue can be solved more easily with the frequent pattern: 通常,使用频繁模式可以更轻松地解决此类问题:
x = lambda y=y: ...
where the value y
is copied as default for an optional parameter of the lambda. 默认情况下,将值y
复制为lambda的可选参数。
In your case however this approach is not possible because at the time the lambda
is evaluated the Button
instance doesn't exist yet (so you cannot store it as a default parameter value in the lambda itself). 但是,在您的情况下,这种方法是不可能的,因为在评估lambda
, Button
实例尚不存在(因此,您无法将其作为默认参数值存储在lambda本身中)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.