2012-10-31 91 views
2

銷燬綁定到外部窗口小部件的窗口時出現問題。破壞後綁定活着

例如,我有一個根窗口和許多不同的子窗口(在代碼中是簡單的)。

當我從根打開子窗口。 它創建一個窗口並綁定到來自根窗口的信號。 所有的子窗口都會綁定到這個相同的信號,但不同的回調(每個子窗口一個)。

然後,當我銷燬這個子窗口(點擊頂角的X)時,綁定仍然存在,這意味着子窗口仍然存在。

現在的問題是: 如何使用其綁定來銷燬子窗口,讓其他回調活着?

在子窗口_destroy方法,我都試過

root.unbind("<<EverybodyDoSomething>>", self.bind1) 

,但我得到一個錯誤

TclError: can't delete Tcl command

如果我用

root.unbind("<<EverybodyDoSomething>>") 

所有的回調與信號的產生密切相關得到解凍。

import Tkinter as Tk 

root = Tk.Tk() 
i_window = 0 

def generate_dosomething_signal(): 
    root.event_generate('<<EverybodyDoSomething>>', when = 'tail') 

def subwindow(): 
    SubWindow() 

class SubWindow(Tk.Tk): 
    def __init__(self): 
     global i_window 
     Tk.Tk.__init__(self) 
     self.i = str(i_window) 
     i_window += 1 
     l = Tk.Label(master=self, text='This is s Sub Window %s!!!!'%self.i) 
     l.pack() 
     self.bind1 = root.bind('<<EverybodyDoSomething>>', 
           self.callback_from_sub_window, '+') 

     self.bind('<Destroy>', self._destroy) 

    def _destroy(self, *args): 
#  root.unbind('<<EverybodyDoSomething>>', self.bind1) 
#  root.unbind('<<EverybodyDoSomething>>') 
     pass 

    def callback_from_sub_window(self, *args): 
     print 'callback from Sub Window ' + self.i 

bStartWindow = Tk.Button(master=root, text='Start Sub Window', command=subwindow) 
bStartWindow.pack() 

bDoSomethingEverywhere = Tk.Button(master=root, text='Do something everywhere', 
            command = generate_dosomething_signal) 
bDoSomethingEverywhere.pack() 

root.mainloop() 

回答

0

你說的不是Tkinter的正常行爲。通常,當你銷燬一個小部件時,它的所有子部件也會被銷燬。當它們被摧毀時,它們的綁定就隨之而來。

很可能,問題的根源在於您正在創建多個根小部件的實例。你根本無法做到這一點。一個Tkinter應用程序必須只有一個Tk實例,並且恰好有一個正在運行的實例mainloop

如果您想要多個頂級窗口,請爲第二個和後續窗口創建Toplevel的實例。

此外,您不應該使用bind(...,"+")來完成此任務。正如你發現的那樣,沒有辦法去除這種綁定。您可以完全刪除與<<EverybodyDoSomething>>的所有綁定,但不能刪除僅添加了bind(..."+")的一個部分。

你需要做的只是調用單個函數的單個綁定。然後該函數可以迭代頂層窗口列表,將事件發送到每個窗口。你可以簡單地跳過任何不存在的窗口。您可以使用自省來獲取頂級窗口的列表,或者您可以通過每次創建代碼時附加窗口引用來手動維護該列表。

+0

感謝您的信息,我不知道Toplevel(Tkinter新手),但是在Tk改換Toplevel後,問題依然存在。創建一個或多個子窗口後,如果關閉它們,「do something button」不應該做任何事情,但它仍會調用被銷燬的子窗口的回調。 – fariza

+0

爲了澄清,我想要的是子窗口和它們的回調被銷燬,而不是根窗口。 – fariza

+0

@fariza:我已經更新了我的答案。簡短的回答:你不能像你這樣去除綁定。你需要改變你的架構。 –

0

這完成你想要什麼:

import Tkinter as Tk 

root = Tk.Tk() 
i_window = 0 

def generate_dosomething_signal(): 
    global root 
    root.event_generate('<<EverybodyDoSomething>>', when = 'tail') 

def subwindow(): 
    global root 
    SubWindow(root) 

class SubWindow(): 
    def __init__(self, root): 
     global i_window 
     self.root = root 

     self.subwindow = Tk.Toplevel() 
     self.i = str(i_window) 
     self.destroyed = False 
     i_window += 1 
     l = Tk.Label(master=self.subwindow, text='This is s Sub Window %s!!!!'%self.i) 
     l.pack() 
     self.bind1 = self.root.bind('<<EverybodyDoSomething>>', 
           self.callback_from_sub_window, '+') 
     self.subwindow.protocol("WM_DELETE_WINDOW", self._destroy) 
     #self.subwindow.bind('<Destroy>', self._destroy) 

    def _destroy(self, *args): 
     self.subwindow.destroy() 
     self.destroyed = True 
     print "Destroyed ", self.i 


    def callback_from_sub_window(self, *args): 
     if self.destroyed == False: 
      print 'callback from Sub Window ' + self.i 


bStartWindow = Tk.Button(master=root, text='Start Sub Window', command=subwindow) 
bStartWindow.pack() 

bDoSomethingEverywhere = Tk.Button(master=root, text='Do something everywhere', 
            command = generate_dosomething_signal) 
bDoSomethingEverywhere.pack() 

root.mainloop() 

明確,他們告訴你,你需要創建一個子窗口爲toplevels。此外,請注意,每次創建Subwindow()python對象時,它都是指向根窗口的指針,該窗口綁定到EverybodyDoSomething>>事件,然後作爲回調附加函數callback_from_sub_window()的本地實例。 。儘管窗口被破壞(從Tk的角度來看),但這種子窗口的Subwindow()對象仍然存在,因此它的callback_from_sub_window()函數仍然存在。就像對事件作出反應的根窗口一樣,去執行每個創建(和/或銷燬)子窗口的「private」callback_from_sub_window()函數。在Subwindow()類中安裝self.destroyed標誌可以防止銷燬的子窗口作爲回調作出反應。

+0

這實際上並沒有做我想做的事情,它只是假裝銷燬,實例還活着,所以內存泄漏。 – fariza