2013-06-11 11 views
5

Wie soll ich Kind Toplevel() Windows in tkinter spawn, die nicht schließen, wenn das Elternteil schließt?Machen Sie tkinter Toplevel-Fenster, das nicht mit dem Elternteil schließt

Muss ich die Eltern behalten eine 'Referenz Anzahl' von Kind Windows, abfangen WM_DELETE_WINDOW und nur anrufen root.destroy(), wenn alle Kinder weg sind?

Oder ist es akzeptable Praxis, einen anderen Thread Prozess mit einem eigenen tk mainloop zu spawnen?

Oder gibt es einen eleganteren Weg?

EDIT

Ich bin derzeit die Dinge auf diese Weise

root = Tk() 
app = App(root) # doesn't call Toplevel() 
root.mainloop() 

tun, wo App.__init__() Widgets root fügt ohne Toplevel() Aufruf, und irgendwann laicht ein neues Fenster mit dieser Funktion:

def new_window(): 
    root = Tk() 
    window = App2(root) # doesn't call Toplevel() either 

Beachten Sie, dass root in new_window() ist eine andere Variable als die ursprüngliche root, erhalten durch einen anderen Anruf an Tk().

All dies scheint zu tun Das richtige Ding, d. H. Das Kindfenster lebt unabhängig von dem Elternteil und der Pythonprozess stirbt, nachdem beide geschlossen sind.

Also meine Frage wird, macht das Sinn oder mache ich hier etwas schrecklich falsch?

Antwort

1

Anstatt zu verfolgen, welche Toplevels am Leben sind, könnten Sie eine weakref auf einem Sentinel verwenden - nur ein Objekt, das an jede Toplevel übergeben und in einer Referenz gespeichert wird. Wenn jeder Toplevel stirbt (geschlossen ist), lasst er seine Referenz auf den Sentinel löschen. Wenn der letzte Verweis auf den Sentinel gelöscht wird, wird der weakref-Callback self.no_sentinel automatisch aufgerufen, der wiederum root.destroy für Sie aufruft.

import Tkinter as tk 
import weakref 


class Sentinel(object): 
    pass 


class Window(tk.Toplevel): 
    def __init__(self, master, sentinel, **kwargs): 
     title = kwargs.pop('title') 
     self.sentinel = sentinel 
     tk.Toplevel.__init__(self, master, **kwargs) 
     self.protocol("WM_DELETE_WINDOW", self.ondelete) 
     self.label = tk.Label(self, text=title) 
     self.label.pack(padx=10, pady=10) 

    def ondelete(self): 
     self.destroy() 
     del self.sentinel 


class App(object): 
    def __init__(self, master, **kwargs): 
     self.master = master 
     sentinel = Sentinel() 
     parent = Window(master, sentinel, title='Parent') 
     child = Window(master, sentinel, title='Child') 
     self._ref = weakref.ref(sentinel, self.no_sentinel)    
     # When we exit `__init__` only two strong references to sentinal 
     # remain -- in parent and child. When both strong references are 
     # deleted, `self.no_sentinel` gets called. 
    def no_sentinel(self, *args): 
     self.master.destroy() 

root = tk.Tk() 
root.withdraw() 
app = App(root) 
root.mainloop() 

Alternativ Sie könnte verwenden Sie das multiprocessing Modul einen anderen Prozess zum Laichen andere Tkinter Fenster und mainloop zu machen, aber würde der Verbraucher mehr Speicher als die Lösung oben sein, und möchten Sie Setup eine Form von Inter erfordern Kommunikation, wenn Sie möchten, dass die separaten Prozesse Informationen gemeinsam nutzen.

+0

Ich erhalte jetzt eine neue Wurzel mit 'tk.Tk()', aber rufe 'hoistloop()' nicht wieder auf - das scheint zu funktionieren, während es viel einfacher ist - irgendeine Idee, warum das sein könnte? Sie würden denken, 'Tk()' wäre ein Singleton, der denselben Master zurückgibt, aber das Erstellen von Widgets scheint das erste Fenster nicht zu beeinflussen. –

+0

Btw siehe meine Bearbeitung der ursprünglichen Frage - ich meinte Prozess nicht thread. –

+1

Ich bin mir nicht ganz sicher, ob ich deine Frage verstehe. Es gibt einen viel einfacheren Weg als das, was ich oben zeige - benutze einfach Toplevels und rufe 'root.withdraw()' auf - aber dann kannst du alle deine Toplevels schließen und das Programm läuft immer noch im Hintergrund. Sie werden auf diese Weise Zombie-Prozesse ansammeln. Der Zweck des oben genannten Fehlers ist es, das Programm zu beenden, wenn der letzte Toplevel geschlossen wird. Wenn ich deine Frage nicht beantworte, poste bitte deinen Code. – unutbu

Verwandte Themen