Tkinter中IntVar绑定CheckButton失效问题求助
问题根源与解决方案
嘿,这个问题我太熟了!你遇到的核心问题是InfoRow的实例没有被MainFrame保留引用,导致Python的垃圾回收机制把这些实例(包括里面的IntVar变量)给回收了——虽然你打印的时候变量值是对的,但Tkinter已经失去了对这些变量的追踪,所以Checkbutton只能显示默认的未勾选状态。
为什么会这样?
在你的MainFrame.addInfo方法里,你创建了InfoRow实例,但只是创建完就完事了,没有把它们存在MainFrame的某个属性里。Python会把这种没有被任何地方引用的临时对象标记为可回收,很快就会清理掉。而Tkinter的变量(比如IntVar)依赖于Python层面的引用才能和GUI组件保持绑定,一旦引用没了,变量就失效了。
怎么修复?
只需要在MainFrame里加个列表,把所有创建的InfoRow实例存进去就行,步骤很简单:
- 在MainFrame的
__init__方法里初始化一个空列表,用来保存InfoRow实例 - 每次创建InfoRow后,把它添加到这个列表里
修改后的完整代码
mainframe.py
from Tkinter import * import ttk import inforow testinfo = {'ITEM 1': {'one':1, 'two':0, 'three':1} , 'ITEM 2': {'one':0, 'two':1, 'three':0}} class MainFrame(Frame): def __init__(self, parent=None, **options): Frame.__init__(self, parent, **options) self.pack(expand=YES, fill=BOTH) self.info_rows = [] # 新增:用来保存所有InfoRow实例,防止被回收 self.addHeader() self.addInfo(testinfo) def addHeader(self): Label(self, text="Item").grid(row=0,column=0) Label(self, text="one").grid(row=0,column=1) Label(self, text="two").grid(row=0,column=2) Label(self, text="three").grid(row=0,column=3) def addInfo(self, info): row = 1 for item in info: # 创建实例后保存到列表里 info_row = inforow.InfoRow(self, row, item, info[item]) self.info_rows.append(info_row) row += 1 if __name__ == "__main__": root = Tk() MainFrame(root) root.mainloop()
inforow.py
(这部分代码不用改,贴出来方便你直接使用)
from Tkinter import * import ttk class InfoRow(): def __init__(self, root, row, item, values): self.chkUsedVar1 = IntVar() self.chkUsedVar1.set(values["one"]) self.chkUsedVar2 = IntVar() self.chkUsedVar2.set(values["two"]) self.chkUsedVar3 = IntVar() self.chkUsedVar3.set(values["three"]) self.skillLabel = Label(root, width=10, text=item, anchor="w") self.skillLabel.grid(row=row,column=0,sticky=W) self.usedChkButton1 = Checkbutton(root, text='Used1', variable=self.chkUsedVar1) self.usedChkButton1.grid(row=row,column=1) self.usedChkButton2 = Checkbutton(root, text='Used2', variable=self.chkUsedVar2) self.usedChkButton2.grid(row=row,column=2) self.usedChkButton3 = Checkbutton(root, text='Used3', variable=self.chkUsedVar3) self.usedChkButton3.grid(row=row,column=3) print 'Row ' + item print self.chkUsedVar1.get() print self.chkUsedVar2.get() print self.chkUsedVar3.get() print
现在再运行mainframe.py,Checkbutton就会正确显示你设置的勾选状态啦!
另外提个小建议:其实让InfoRow继承自Frame,把所有组件都放在这个Frame里再布局到MainFrame,是更规范的Tkinter写法,也能避免这类引用问题,不过上面的修改已经完全能解决你当前的问题了。
内容的提问来源于stack exchange,提问作者fingletoe
相关产品推荐
相关产品推荐

