Tkinker列表框绑定似乎不起作用

时间:2016-02-24 19:57:51

标签: python tkinter

我从控制台脚本启动一个简单的对话框来显示一个项目列表,应该关闭一个列表元素被双击。我隐藏了根,并等待脚本继续执行操作。然而,当我双击列表元素时没有任何反应,尽管有些消息应该在控制台中打印出来。

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()

有什么想法吗?

编辑:根据吉尔的回答,我编辑了我的代码:

  • 现在,该方法称为_get_selection,以避免与self.selection变量冲突。即使我不使用该方法,该方法也会收到一个事件
  • 我打电话给主循环,并删除了Toplevel。该类现在继承自Tkinker.Tk,因此它实现了一个退出方法。

尽管如此,它仍然无效。对话框显示,但是当我双击(甚至不是错误)时,控制台中没有任何内容被打印出来。 我错过了什么?

代码:

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)

1 个答案:

答案 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)