通过 tkinter 的绑定方法通信 类
Communicate classes via tkinter's bind method
我正在使用 tkinter
开发带有 GUI 的软件包。现在通过 tkinter 的 bind 方法与 classes 通信时出现问题。下面列出了代表我想做的事情的简单代码:
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()
class selects
采用 Listbox
小部件 select 中的一个值 lists
和 return selected 值通过属性 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'
我认为这个错误可以通过将 classes selects
和 do
合并为一个 class 来解决。但是在我的包中,class selects
会被多个 class 调用,所以最好将 selects
作为一个独立的 class。此外,像这样的 class 之间的通信将经常应用在我的包中。例如,在使用 pick_event
在 matplotlib
中选择一些信息后做一些事情,或者在使用 Entry
在另一个 class 中输入文本后更新一个 class 中的列表小部件。那么,对此有什么建议吗?提前致谢。
您在创建 sl
后立即调用 sl.returnvalue()
。但是,此时sl.getvalue()
还没有被调用,也就是说sl.selectvalue
还不存在
如果我正确理解您想做什么,您应该在创建 sl
(sl = selects(root)
) 之后立即调用 root.mainloop()
。这样,Tk 进入主循环,运行s 直到 window 被销毁,即用户双击其中一个值时。然后,sl.getvalue()
变成了 运行,程序可以继续调用 sl.returnvalue()
而不会出错。
由于您实际上并没有在该部分代码中调用主循环,因此我更改了您的代码以反映这一点,并且仍然可以按您希望的方式工作。其中的一个关键方法是 wait_window
,它会在本地事件循环中停止执行,直到 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()
我正在使用 tkinter
开发带有 GUI 的软件包。现在通过 tkinter 的 bind 方法与 classes 通信时出现问题。下面列出了代表我想做的事情的简单代码:
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()
class selects
采用 Listbox
小部件 select 中的一个值 lists
和 return selected 值通过属性 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'
我认为这个错误可以通过将 classes selects
和 do
合并为一个 class 来解决。但是在我的包中,class selects
会被多个 class 调用,所以最好将 selects
作为一个独立的 class。此外,像这样的 class 之间的通信将经常应用在我的包中。例如,在使用 pick_event
在 matplotlib
中选择一些信息后做一些事情,或者在使用 Entry
在另一个 class 中输入文本后更新一个 class 中的列表小部件。那么,对此有什么建议吗?提前致谢。
您在创建 sl
后立即调用 sl.returnvalue()
。但是,此时sl.getvalue()
还没有被调用,也就是说sl.selectvalue
还不存在
如果我正确理解您想做什么,您应该在创建 sl
(sl = selects(root)
) 之后立即调用 root.mainloop()
。这样,Tk 进入主循环,运行s 直到 window 被销毁,即用户双击其中一个值时。然后,sl.getvalue()
变成了 运行,程序可以继续调用 sl.returnvalue()
而不会出错。
由于您实际上并没有在该部分代码中调用主循环,因此我更改了您的代码以反映这一点,并且仍然可以按您希望的方式工作。其中的一个关键方法是 wait_window
,它会在本地事件循环中停止执行,直到 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()