Tkinter:命名StringVar时类实例问题

Tkinter:命名StringVar时类实例问题,tkinter,callback,trace,Tkinter,Callback,Trace,全部,, 我对这件事有点困惑,希望有人能解释发生了什么 这个例子有点令人费解,但它说明了我在应用程序中看到的问题。我有三个扩展Tkinter.Frame的类;A、 B和X.B包含A的一个实例和一个变量(标签),其值取决于A中选项菜单的状态。X有多个B的实例。当我在下面的行(从类A)中设置name='opt_var'时,X中的b1和b2就好像它们是B的同一个实例一样 self.opt_var = StringVar(name='opt_var') 但是,当我从StringVar声明中删除name

全部,, 我对这件事有点困惑,希望有人能解释发生了什么

这个例子有点令人费解,但它说明了我在应用程序中看到的问题。我有三个扩展Tkinter.Frame的类;A、 B和X.B包含A的一个实例和一个变量(标签),其值取决于A中选项菜单的状态。X有多个B的实例。当我在下面的行(从类A)中设置name='opt_var'时,X中的b1和b2就好像它们是B的同一个实例一样

self.opt_var = StringVar(name='opt_var')
但是,当我从StringVar声明中删除name='opt_var'时,我得到了两个独立实例的预期(即独立)行为

更让我困惑的是,我使用“b1是b2”对B的两个实例进行了比较——我理解这是为了检查两个变量是否指向同一个对象——我得到了真值,这是出乎意料的,因为b1和b2是分开实例化的

任何对正在发生的事情的洞察都是值得赞赏的

from Tkinter import *
import collections

# A simple class with an Option Menu
class A(Frame):
    def __init__(self, master):
        Frame.__init__(self, master)

        self.opt_dict = collections.OrderedDict()
        self.opt_dict['Option A'] = 0
        self.opt_dict['Option B'] = 1
        keys = self.opt_dict.keys()

        self.opt_var = StringVar(name='opt_var')
        self.opt_var.set(keys[0])
        opt_om = OptionMenu(self, self.opt_var, *keys).pack()

# A simple class with a Label whose value is determined by Class A's option
class B(Frame):
    def __init__(self, master):
        Frame.__init__(self, master)

        self.lbl = Label(self, text='What did you choose?')
        self.lbl.pack()

        self.a = A(self)
        self.a.pack()
        # set a 'trace' on a's StringVar with a local callback
        self.a.opt_var.trace('w', self.myfunction)

    def myfunction(self, *args):
        # this seems a little convoluted here but in the app where I 
        # came across this issue, there are more than just two choices
        optB = bool(self.a.opt_dict[self.a.opt_var.get()])
        if (optB):
            self.lbl.config(text='Option B') 
        else:
            self.lbl.config(text='Option A') 

# a simple class with multiple instances of B            
class X(Frame):
    def __init__(self, master):
        Frame.__init__(self, master)        
        b1 = B(self).pack()
        b2 = B(self).pack()

        print(b1 is b2)

root = Tk()
frame = X(root).pack()
root.mainloop()

Tkinter是嵌入式Tcl解释器的薄包装。这个解释器对python名称空间一无所知

当您创建
StringVar
的实例时,这将在该Tcl解释器中创建一个新的全局变量。通常Tkinter会选择一个唯一的变量名。当您显式地给它一个名称时,它将成为全局变量的名称。如果创建多个
StringVar
实例并为每个实例指定相同的名称,则它们都将绑定到同一个Tcl变量


解决方案很简单:类的每个实例都需要创建一个具有唯一名称的
StringVar
实例。

感谢您的解释。Tkinter不符合基本的面向对象原则似乎有些奇怪。