import Tkinter as tk
class MyApp(tk.Tk):
'''Example app that uses Tcl arrays'''
def __init__(self):
tk.Tk.__init__(self)
self.arrayvar = ArrayVar()
self.labelvar = tk.StringVar()
rb1 = tk.Radiobutton(text="one", variable=self.arrayvar("radiobutton"), value=1)
rb2 = tk.Radiobutton(text="two", variable=self.arrayvar("radiobutton"), value=2)
cb = tk.Checkbutton(text="checked?", variable=self.arrayvar("checkbutton"),
onvalue="on", offvalue="off")
entry = tk.Entry(textvariable=self.arrayvar("entry"))
label = tk.Label(textvariable=self.labelvar)
spinbox = tk.Spinbox(from_=1, to=11, textvariable=self.arrayvar("spinbox"))
button = tk.Button(text="click to print contents of array", command=self.OnDump)
for widget in (cb, rb1, rb2, spinbox, entry, button, label):
widget.pack(anchor="w", padx=10)
self.labelvar.set("Click on a widget to see this message change")
self.arrayvar["entry"] = "something witty"
self.arrayvar["radiobutton"] = 2
self.arrayvar["checkbutton"] = "on"
self.arrayvar["spinbox"] = 11
self.arrayvar.trace(mode="w", callback=self.OnTrace)
def OnDump(self):
'''Print the contents of the array'''
print self.arrayvar.get()
def OnTrace(self, varname, elementname, mode):
'''Show the new value in a label'''
self.labelvar.set("%s changed; new value='%s'" % (elementname, self.arrayvar[elementname]))
class ArrayVar(tk.Variable):
'''A variable that works as a Tcl array variable'''
_default = {}
_elementvars = {}
def __del__(self):
self._tk.globalunsetvar(self._name)
for elementvar in self._elementvars:
del elementvar
def __setitem__(self, elementname, value):
if elementname not in self._elementvars:
v = ArrayElementVar(varname=self._name, elementname=elementname, master=self._master)
self._elementvars[elementname] = v
self._elementvars[elementname].set(value)
def __getitem__(self, name):
if name in self._elementvars:
return self._elementvars[name].get()
return None
def __call__(self, elementname):
'''Create a new StringVar as an element in the array'''
if elementname not in self._elementvars:
v = ArrayElementVar(varname=self._name, elementname=elementname, master=self._master)
self._elementvars[elementname] = v
return self._elementvars[elementname]
def set(self, dictvalue):
# this establishes the variable as an array
# as far as the Tcl interpreter is concerned
self._master.eval("array set {%s} {}" % self._name)
for (k, v) in dictvalue.iteritems():
self._tk.call("array","set",self._name, k, v)
def get(self):
'''Return a dictionary that represents the Tcl array'''
value = {}
for (elementname, elementvar) in self._elementvars.iteritems():
value[elementname] = elementvar.get()
return value
class ArrayElementVar(tk.StringVar):
'''A StringVar that represents an element of an array'''
_default = ""
def __init__(self, varname, elementname, master):
self._master = master
self._tk = master.tk
self._name = "%s(%s)" % (varname, elementname)
self.set(self._default)
def __del__(self):
"""Unset the variable in Tcl."""
self._tk.globalunsetvar(self._name)
if __name__ == "__main__":
app=MyApp()
app.wm_geometry("400x200")
app.mainloop()
已经很晚了,但是,有人发现了一些可能有用的东西。
整个想法来自@bryan Oakley's post
如果我理解的好,主要的问题是检测入口小部件的。要在
spinbox
、Checkbutton
和Radiobutton
中检测它,可以在创建小部件时使用command
选项。要捕获
<onChange>
中的Entry
小部件,可以使用Bryan使用Tcl的方法,生成此事件。正如我所说,这不是我的解决方案,我只是稍微改变了一下。例如:
当然,修改它来为大量实例创建不同的回调(正如您在问题中提到的那样)现在很容易。
我希望有人会发现它有用。
在Tcl中解决这个问题的方法是确保checkbutton、spinbox和radiobutton小部件都与数组变量相关联。然后我会在数组上放置一个跟踪,这样每次写入变量时都会调用一个函数。Tcl让这件事变得微不足道。
不幸的是,Tkinter不支持使用Tcl数组。幸运的是,入侵相当容易。如果你喜欢冒险,试试下面的代码。
来自全面披露部门:我今天早上花了大约半个小时才把这一点整理好。实际上我没有在任何实际的代码中使用过这种技术。不过,我还是忍不住要想办法在Tkinter中使用数组。
我认为正确的方法是对已分配给小部件的tkinter变量使用
trace
。例如。。。
trace中的
w
告诉tkinter每当有人写入(更新)变量时(每次有人在Entry小部件中写入某些内容时都会发生这种情况),执行oddblue
。跟踪总是将三个值传递给您列出的任何函数,因此您需要在函数中使用它们,因此a,b,c
。我通常什么都不做,因为我所需要的一切都是在本地定义的。据我所知,a
是变量对象,b
是空白的(不知道为什么),而c
是跟踪模式(即w
)。For more info on tkinter variables check this out.
相关问题 更多 >
编程相关推荐