我正在使用tkinter
开发一个包含GUI的包。现在通过tkinter的bind方法传递类时出现问题。下面列出了一个代表我想要做的简单代码:
import Tkinter as tk
lists = [1,2,3,4,5,6,7]
class selects():
def __init__(self,root):
self.root = root
self.selectwin()
def selectwin(self):
""" listbox and scrollbar for selection """
sb = tk.Scrollbar(self.root)
lb = tk.Listbox(self.root, relief ='sunken', cursor='hand2')
sb.config(command=lb.yview)
sb.pack(side=tk.RIGHT, fill=tk.Y)
lb.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
lb.config(yscrollcommand=sb.set, selectmode='single')
for value in lists: lb.insert(tk.END,value)
lb.bind('<Double-1>',lambda event: self.getvalue())
self.listbox = lb
def getvalue(self):
""" get the selected value """
value = self.listbox.curselection()
if value:
self.root.quit()
text = self.listbox.get(value)
self.selectvalue = int(text)
def returnvalue(self):
return self.selectvalue
class do():
def __init__(self):
root = tk.Tk()
sl = selects(root)
# do something... for example, get the value and print value+2, as coded below
value = sl.returnvalue()
print value+2
root.mainloop()
if __name__ == '__main__':
do()
类selects
采用Listbox
窗口小部件在lists
中选择一个值,并通过属性returnvalue
返回所选值。但是,运行上述代码时会出错:
Traceback (most recent call last):
File "F:\Analysis\Python\fpgui\v2\test2.py", line 47, in <module>
do()
File "F:\Analysis\Python\fpgui\v2\test2.py", line 41, in __init__
value = sl.returnvalue()
File "F:\Analysis\Python\fpgui\v2\test2.py", line 32, in returnvalue
return self.selectvalue
AttributeError: selects instance has no attribute 'selectvalue'
我认为可以通过将类selects
和do
组合在一起作为单个类来解决此错误。但是在我的包中,类selects
将由几个类调用,因此最好将selects
作为独立类。此外,像这样的类之间的通信将经常应用在我的包中。例如,使用matplotlib
在pick_event
图中选择一些信息后执行某些操作,或者在使用Entry
窗口小部件在另一个类中输入文本后更新一个类中的列表。那么,有什么建议吗?提前谢谢。
答案 0 :(得分:4)
您在创建sl.returnvalue()
后立即致电sl
。但是,此时sl.getvalue()
从未被调用过,这意味着sl.selectvalue
尚不存在。
如果我理解您要正确执行的操作,则应在创建root.mainloop()
(sl
)后立即将呼叫移至sl = selects(root)
。这样,Tk命中主循环,直到窗口被破坏为止,这是用户双击其中一个值。然后,sl.getvalue()
已经运行,程序可以继续调用sl.returnvalue()
而不会出错。
由于您实际上并未在代码的该部分中调用mainloop,因此我已更改您的代码以反映该代码并仍然按您的意愿工作。其中的一个关键方法是wait_window
,它停止在本地事件循环中执行,直到窗口被销毁。我使用this effbot page on Dialog Windows作为参考:
import Tkinter as tk
lists = [1,2,3,4,5,6,7]
class selects():
def __init__(self,root):
self.root = root
self.selectwin()
def selectwin(self):
""" listbox and scrollbar for selection """
sb = tk.Scrollbar(self.root)
lb = tk.Listbox(self.root, relief ='sunken', cursor='hand2')
sb.config(command=lb.yview)
sb.pack(side=tk.RIGHT, fill=tk.Y)
lb.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
lb.config(yscrollcommand=sb.set, selectmode='single')
for value in lists: lb.insert(tk.END,value)
lb.bind('<Double-1>',lambda event: self.getvalue())
self.listbox = lb
def getvalue(self):
""" get the selected value """
value = self.listbox.curselection()
if value:
self.root.quit()
text = self.listbox.get(value)
self.selectvalue = int(text)
self.root.destroy() # destroy the Toplevel window without needing the Tk mainloop
def returnvalue(self):
return self.selectvalue
class do():
def __init__(self, master):
self.top = tk.Toplevel()
self.top.transient(master) # Make Toplevel a subwindow ow the root window
self.top.grab_set() # Make user only able to interacte with the Toplevel as long as its opened
self.sl = selects(self.top)
self.top.protocol("WM_DELETE_WINDOW", self.sl.getvalue) # use the if value: in getvalue to force selection
master.wait_window(self.top) # Wait until the Toplevel closes before continuing
# do something... for example, get the value and print value+2, as coded below
value = self.sl.returnvalue()
print value+2
if __name__ == '__main__':
root = tk.Tk()
d = do(root)
root.mainloop()