Tkinter widget.cget'变量'

问题描述

如何使用cget('variable')方法获取对小部件的控制变量的引用? 我正在寻找一种使用cget('variable')返回的对象来找到关联的tkinter.Intvar对象的解决方案。

import tkinter as tk

root = tk.Tk()

var = tk.Intvar()
print('tkinter variable is of type',type(var)) # <class 'tkinter.Intvar'>

button = tk.Checkbutton(root,text='Checkbutton 1',variable=var)
button.pack(side=tk.TOP,padx=10,pady=10)

# Now I attempt to retrieve "var",using cget('variable').
var2 = button.cget('variable')

print('cget("variable") returns an object of type',type(var2)) # <class '_tkinter.Tcl_Obj'>
print(var is var2) # False

root.mainloop()

解决方法

省去很多麻烦,只需将IntVar存储在按钮上

var        = tk.IntVar()
button     = tk.Checkbutton(root,text='Checkbutton 1',variable=var)
button.var = var         # keep a reference on the button itself

或这样

button     = tk.Checkbutton(root,text='Checkbutton 1')
button.var = tk.IntVar()
button.configure(variable=button.var)

除非您的真正目标是无需参考即可获取价值,否则您可以这样做:

value = button.getvar(str(button.cget("variable")))
print(value)

作为替代,您可以使用我很久以前制作的这个小类。它主要只是使一切自动化,但是它还允许您将一些任意数据与Checkbutton关联。

class Checkbox(tk.Checkbutton):
    @property
    def var(self):
        return self.__var
        
    @property
    def value(self) -> int:
        return self.__var.get()
        
    @value.setter
    def value(self,value):
        self.__var.set(int(bool(value)))
        
    def __init__(self,master,data=None,on_change=None,on_read=None,**kwargs):
        self.__var = tk.IntVar() if not 'variable' in kwargs else kwargs['variable']
        tk.Checkbutton.__init__(self,**{**kwargs,'variable':self.__var})
        self.data = self['text'] if not data else data
            
        if on_change:
            self.__var.trace('w',lambda *a:on_change(self))
            
        if on_read:
            self.__var.trace('r',lambda *a:on_read(self))

以下是一些示例用法

#example 1
def on_change(checkbox):
    print(checkbox.data,checkbox.value)

Checkbox(root,on_change=on_change,text='tester1').grid()
Checkbox(root,text='tester2').grid()

#-----------------------------------------------------------
#example 2
cbs = [
    Checkbox(root,text='test1'),Checkbox(root,text='test2'),text='test3'),text='test4'),]

for i,cb in enumerate(cbs):
    cb.grid(row=0,column=i)
 
def get_values():
    print(*[f'{cb.data}:{cb.value}' for cb in cbs],sep='\n')
    
tk.Button(root,text="check",command=get_values).grid()

#-----------------------------------------------------------
#example 3
def on_read(checkbox):
    if checkbox.data is True:
        if checkbox.value:
            pass
        else:
            pass
    
cb = Checkbox(root,on_read=on_read,data=(someCondition is True),text='tester1')
cb.grid()
#...
something = cb.value  #triggers on_read