python - 二维数组中的 Tkinter 按钮绑定到相同的命令
问题描述
我正在制作一个简单的程序,它创建一个 3x3 矩阵,tkinter.Button()
当按下按钮时,它应该在其上显示“单击”文本。但结果似乎位于同一列上的按钮被绑定到同一个命令 - 该命令以该列最后一行的按钮为目标。
from tkinter import *
root = Tk()
text = [[None]*3]*3
buttons = [[None]*3]*3
def action(i, j):
text[i][j].set('Clicked')
for i in range(3):
for j in range(3):
text[i][j] = StringVar()
text[i][j].set('(%d, %d)' % (i,j))
buttons[i][j] = Button(root, command = lambda i=i, j=j : action(i, j))
buttons[i][j].config(textvariable = text[i][j], width = 9, height = 5)
buttons[i][j].grid(row = i, column = j)
root.mainloop()
解决方案
问题不在于您的命令,而在于您创建列表的方式。
当您乘以一个列表时,实际上是乘以对该单个列表的引用(请参阅此问题)。您可以在运行以下代码时看到这一点:
text = [[None]*3]*3
print([id(x) for x in text])
因此,当您更改其中一个列表中的项目时,该项目在所有列表中都会更改。因此,您的列表看起来不像[[1,2,3],[4,5,6],[7,8,9]]
,而是像[[7,8,9],[7,8,9],[7,8,9]]
。然后,当您认为将 StringVar 设置为 1 时,实际上您将 Stringvar 设置为 7,因此更改了按钮 7。
您可以使用列表推导而不是乘法来创建三个单独的列表。正如您在以下代码中看到的那样,这会生成三个单独的列表。
text = [[None]*3 for _ in range(3)]
print([id(x) for x in text])
推荐阅读
- xml - TSQL:如何从 T1.Field_A 中的 XML 信息和 T2.Field_A 中的 nvarchar 的两个表中获取 UNION 结果
- selenium - 如何使用 selenium webdriver (Mac) 上传图像
- c# - 如何在 Xamarin.Forms 上使用 POST 方法将数据发送到 Google 电子表格?
- php - 如果从 laravel 5.5 升级到 5.8 护照不会在 oauth/token url 上生成令牌
- javascript - Fullcalendar 仅删除特定资源组或资源 ID
- android - 谷歌文档查看器不能在本地主机上工作吗?
- spring-boot - 自定义对象映射器在springboot中不生效
- javascript - ReactJS:已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查
- c# - 无法将字符串“名称”转换为字典键类型 - 创建一个 TypeConverter 以从字符串转换为键类型对象
- kubernetes - Spinnaker 中存储设置的自定义配置文件