Tkinter中勾选复选框时如何打印对应复选框名称?
这是一个非常典型的Python lambda延迟绑定问题,我来帮你理清楚问题出在哪,以及怎么修复:
为什么会出现这个问题?
你在循环里给每个复选框的command绑定了lambda: temp(key),但lambda的特性是:它不会在定义的时候就捕获当前的key值,而是等到被调用(也就是你点击复选框)的时候,才会去查找key变量的当前值。
当你的for循环执行完后,key变量最后指向的是metadata_list的最后一个元素'creation',所以不管你点击哪个复选框,lambda都会拿这个最终的key值传给temp(),自然每次都打印最后一个元素了。而你在循环内直接print(key)是正常的,因为那时候是实时读取循环当前的key值,还没到循环结束的最终状态。
两种修复方案
方案1:给lambda添加默认参数(最简便)
修改复选框的command参数,给lambda设置一个默认参数来强制捕获当前循环的key值:
tk.Checkbutton(metadata_frame, text = key.upper(), variable = i[1], command = lambda k=key: temp(k)).grid(row = i[0])
这里的关键是k=key:默认参数是在lambda定义时就求值的,所以每个lambda都会保存自己对应的key值,不会再去引用循环结束后的key变量。
方案2:使用functools.partial(更清晰,适合多参数场景)
如果你觉得lambda的写法不够直观,可以用functools.partial来绑定参数:
首先导入partial:
from functools import partial
然后修改command:
tk.Checkbutton(metadata_frame, text = key.upper(), variable = i[1], command = partial(temp, key)).grid(row = i[0])
partial会把当前循环的key值直接绑定到temp函数的第一个参数上,生成一个独立的函数对象,每个复选框的command都是绑定了对应key的专属函数,逻辑更清晰。
修复后的完整主文件代码(以方案1为例)
import tkinter as tk import variable_container as vc metadata_frame = tk.Tk() def temp(key): print(key) for key,i in vc.metadata_list.items(): i[1] = tk.IntVar() # 用默认参数捕获当前key值 tk.Checkbutton(metadata_frame, text = key.upper(), variable = i[1], command = lambda k=key: temp(k)).grid(row = i[0]) print(key) metadata_frame.mainloop()
额外小提示
你的variable_container.py里的var_copyright、var_location、var_creation在定义前需要先声明(比如设为None),否则运行时会报NameError,修改后的variable_container.py可以是这样:
# Values are the row information and respective checkbox variables var_copyright = None var_location = None var_creation = None metadata_list = { 'copyright': [0, var_copyright], 'location': [1, var_location], 'creation': [2,var_creation] }
内容的提问来源于stack exchange,提问作者Anish

