我从控制台脚本启动一个简单的对话框来显示一个项目列表,应该关闭一个列表元素被双击。我隐藏了根,并等待脚本继续执行操作。然而,当我双击列表元素时没有任何反应,尽管有些消息应该在控制台中打印出来。
import Tkinter as tk
class SelectionList:
def __init__(self, list_of_options):
root = tk.Tk()
self.top = tk.Toplevel(root)
root.withdraw()
self.selection = None
self.initialize(list_of_options)
root.wait_window(self.top)
def initialize(self, list_of_options):
frame = tk.LabelFrame(self.top, text='Select an option')
frame.grid(
row=0, columnspan=1, sticky='W', padx=5, pady=5, ipadx=5, ipady=5)
self.listbox = tk.Listbox(self.top, width=25, height=10)
self.listbox.grid(row=0, column=0, sticky='E', padx=5, pady=2)
for opt in list_of_options:
self.listbox.insert(tk.END, opt)
self.listbox.bind('<Double-1>', self.selection)
def selection(self):
print 'Hello world'
self.selection = self.listbox.get(self.listbox.curselection()[0])
print self.selection
self.quit()
有什么想法吗?
编辑:根据吉尔的回答,我编辑了我的代码:
尽管如此,它仍然无效。对话框显示,但是当我双击(甚至不是错误)时,控制台中没有任何内容被打印出来。 我错过了什么?
代码:
import Tkinter as tk
class SelectionList(tk.Tk):
def __init__(self, list_of_options):
tk.Tk.__init__(self, None)
self.title('Select an option')
self.selection = None
self.initialize(list_of_options)
def initialize(self, list_of_options):
frame = tk.LabelFrame(self, text='Select an option')
frame.grid(
row=0, columnspan=1, sticky='W', padx=5, pady=5, ipadx=5, ipady=5)
self.listbox = tk.Listbox(self, width=25, height=10)
self.listbox.grid(row=0, column=0, sticky='E', padx=5, pady=2)
for opt in list_of_options:
self.listbox.insert(tk.END, opt)
self.listbox.bind('<Double-1>', lambda ev: self._get_selection)
def _get_selection(self, event):
print 'Hello world'
self.selection = self.listbox.get(self.listbox.curselection())
print self.selection
self.quit()
if __name__ == '__main__':
list_of_options = ['a', 'b', 'c', 'd']
dialog = SelectionList(list_of_options)
dialog.mainloop()
print 'Selected: ' + str(dialog.selection)
答案 0 :(得分:2)
有很多问题。
1)您定义了self.selection
两次(或者可能是三次,具体取决于您的计算方式)。有一种名为selection
的方法。然后在__init__
中有一个同名的属性,设置为None
(然后在方法selection
中重置...)。事实上,该方法会被属性遮蔽,因此当您bind
列表框self.selection
时,您将其绑定到None
,因此当您双击时,您将获得TypeError
1}},如果你正在关注控制台。
据我所知,属性selection
并不代表您做任何工作。只需删除它。 self.selection
方法正文中的selection
应重命名为其他内容。如果您不需要记住所选项目,请使用本地变量:
selection = self.listbox.get(self.listbox.curselection()[0])
print(selection)
完成之后:
2)绑定到窗口小部件的函数必须接受事件参数。你的selection
方法不接受它(它需要self
作为第一个参数,并且没有其他参数的余地)。因此,您需要更改selection
的签名或更改绑定的功能。做后者:
self.listbox.bind('<Double-1>', lambda e: self.selection())
3)self.quit
未定义。定义它,或删除它。
<强> PS。强>
@BryanOakley说他应该打电话给root.mainloop()
。确实Toplevel
会自动调用它自己的mainloop
,但组织这样的代码会让人感到惊讶,which is not good。一个更传统的组织是这样的:
class SelectionList:
def __init__(self, master, list_of_options):
self.top = tk.Frame(master)
self.top.pack()
self.initialize(list_of_options)
# ...
if __name__ == '__main__':
root = tk.Tk()
SelectionList(root, ['foo', 'bar'])
root.mainloop()
# You do not need wait_window for what you do
编辑:
我原来的答案中有一个致命的拼写错误:
self.listbox.bind('<Double-1>', lambda e: self.selection)
双击时不会调用self.selection()
。应该是
self.listbox.bind('<Double-1>', lambda e: self.selection())
没有()
,就像在以下代码中调用bar()
一样。 foo()
不会被调用,也不会打印任何内容。
def foo():
print('foo')
def bar():
foo # should be foo()
要充实另一种选择:如果你想避免lambda
,你只需在你编辑过的问题中向self.selection
添加一个事件参数(现在self._get_selection
,但我&#39} ;继续这里的旧版本)。在你的情况下,不会使用事件参数,但这很好。
def selection(self, event):
# no change to the rest
绑定可以很简单(这次没有()
):
self.listbox.bind('<Double-1>', self.selection)