如何定位tkinter按钮数组中被点击的按钮并修改其颜色
问题根因
点击任意按钮都只修改最后一个按钮样式,是Python lambda闭包的典型特性导致的:lambda表达式中引用的循环变量x、y不会在定义时固定值,而是会在实际触发点击时读取变量当前值。等双层循环全部执行完,x和y会停在最后一轮循环的数值上,不管点哪个按钮,传入回调函数的都是最后一组坐标,自然只会操作最后一个创建的按钮。
你之前写的8x8棋盘版本除了上述闭包问题外,回调函数onClick直接写死取tile[-1]也就是按钮列表的最后一个元素,逻辑上也必然只会修改最后一个按钮。
修复方案
核心是给每个按钮的回调函数提前绑定当前循环轮次的坐标值,最简便的写法是利用lambda的默认参数——默认参数会在函数定义时就固定取值,不会随循环变量变动。
修复后的60*20按钮阵列代码
from tkinter import * class testClass: def main(self): root = Tk() frame=Frame(root) frame.grid(row=0,column=0) self.btn= [[0 for x in range(20)] for x in range(60)] for x in range(60): for y in range(20): # 新增x=x、y=y默认参数,绑定当前循环的坐标值 self.btn[x][y] = Button(frame,command= lambda x=x, y=y: self.color_change(x,y)) self.btn[x][y].grid(column=x, row=y) root.mainloop() def color_change(self,x,y): self.btn[x][y].config(bg="red") testMain = testClass() testMain.main()
修复后的8x8棋盘代码
from tkinter import * root = Tk() wd = Frame(root, width = "500", height = "500", bg = "brown") wd.pack( padx = 5, pady = 5) tile = {} # 回调接收当前按钮的坐标 def onClick(x, y): tile[(x,y)].config(bg = "green") for row_idx in range(8): for col_idx in range(8): if 2 <= row_idx <=4: btn = Button(wd, width = 2, height = 1, command = lambda x=row_idx, y=col_idx: onClick(x,y)) btn.grid(padx = 0.5, pady = 0.5, row = row_idx, column = col_idx) tile[(row_idx, col_idx)] = btn elif 0 <= row_idx <=1: btn = Button(wd, width = 2, height = 1, text = "O", fg = "red", command = lambda x=row_idx, y=col_idx: onClick(x,y)) btn.grid(padx = 0.5, pady = 0.5, row = row_idx, column = col_idx) tile[(row_idx, col_idx)] = btn elif 6 <= row_idx <=7: btn = Button(wd, width = 2, height = 1, text = "O", fg = "blue", command = lambda x=row_idx, y=col_idx: onClick(x,y)) btn.grid(padx = 0.5, pady = 0.5, row = row_idx, column = col_idx) tile[(row_idx, col_idx)] = btn root.mainloop()
注意:不要把
mainloop()的返回值赋值给Tk实例变量,会覆盖原窗口对象导致异常,直接调用mainloop()即可。
内容的提问来源于stack exchange,提问作者Arran McLoughlin
相关产品推荐
相关产品推荐

