Tkinter:Class 命名 StringVar 时的实例问题
Tkinter: Class Instance issue when StringVar is Named
全部,
我对这个有点困惑,希望有人能解释这是怎么回事。
这个例子有点复杂,但它可以说明我在我的应用程序中看到的问题。我有三个 类 扩展 Tkinter.Frame; A、B 和 X。B 包含 A 的一个实例和一个变量(标签),其值取决于 A 中选项菜单的状态。X 有多个 B 实例。当我设置 name='opt_var'在下面的行中(来自 Class A),X 中的 b1 和 b2 就像它们是 B.
的同一个实例一样
self.opt_var = StringVar(name='opt_var')
但是,当我从 StringVar 声明中删除 name='opt_var' 时,我得到了两个独立实例的预期(即独立)行为。
更让我困惑的是,我使用 "b1 is b2" 对 B 的两个实例进行了比较——据我所知,这应该检查两个变量是否指向同一个对象——我得到的是 True意外,因为 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 变量。
解决方案很简单:class 的每个实例都需要创建具有唯一名称的 StringVar
实例。
全部, 我对这个有点困惑,希望有人能解释这是怎么回事。
这个例子有点复杂,但它可以说明我在我的应用程序中看到的问题。我有三个 类 扩展 Tkinter.Frame; A、B 和 X。B 包含 A 的一个实例和一个变量(标签),其值取决于 A 中选项菜单的状态。X 有多个 B 实例。当我设置 name='opt_var'在下面的行中(来自 Class A),X 中的 b1 和 b2 就像它们是 B.
的同一个实例一样self.opt_var = StringVar(name='opt_var')
但是,当我从 StringVar 声明中删除 name='opt_var' 时,我得到了两个独立实例的预期(即独立)行为。
更让我困惑的是,我使用 "b1 is b2" 对 B 的两个实例进行了比较——据我所知,这应该检查两个变量是否指向同一个对象——我得到的是 True意外,因为 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 变量。
解决方案很简单:class 的每个实例都需要创建具有唯一名称的 StringVar
实例。