通过tkinter的bind方法传递类

时间:2015-02-03 04:57:24

标签: python class tkinter

我正在使用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'

我认为可以通过将类selectsdo组合在一起作为单个类来解决此错误。但是在我的包中,类selects将由几个类调用,因此最好将selects作为独立类。此外,像这样的类之间的通信将经常应用在我的包中。例如,使用matplotlibpick_event图中选择一些信息后执行某些操作,或者在使用Entry窗口小部件在另一个类中输入文本后更新一个类中的列表。那么,有什么建议吗?提前谢谢。

1 个答案:

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