2013-06-11 12 views
5

Come dovrei generare figli in Toplevel() finestre in tkinter che non si chiudono quando il genitore si chiude?Crea finestra di tkinter di primo livello che non si chiude con il genitore

Devo fare in modo che il genitore mantenga un "conteggio di riferimenti" di finestre figlio, intercettare WM_DELETE_WINDOW e chiamare solo root.destroy() quando tutti i bambini se ne sono andati?

Oppure è prassi accettabile generare un altro thread thread con il proprio tk mainloop?

O c'è un modo più elegante?

EDIT

Attualmente sto facendo le cose in questo modo

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

dove App.__init__() aggiunge i widget per root senza chiamare Toplevel(), e ad un certo punto genera una nuova finestra con questa funzione:

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

Si noti che root in new_window() è una variabile diversa dall'originale root, ottenuta da un'altra chiamata a Tk().

Tutto ciò sembra fare la cosa giusta, ovvero la finestra figlio vive indipendentemente dal genitore e il processo python muore dopo che entrambi sono stati chiusi.

Quindi la mia domanda diventa, ha senso o sto facendo qualcosa di terribilmente sbagliato qui?

risposta

1

Invece di dover tenere traccia di quali Toplevel sono vivi, è possibile utilizzare un weakref su una sentinella - solo un oggetto che viene passato a ogni Toplevel e salvato in un riferimento. Quando ciascun Toplevel muore (è chiuso), cancella il suo riferimento alla sentinella. Quando viene eliminato l'ultimo riferimento alla sentinella, il callback weakref, self.no_sentinel verrà chiamato automaticamente, a sua volta chiamando root.destroy per te.

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

alternativa, è potrebbe utilizzare il modulo multiprocessing per generare un altro processo per fare un'altra finestra Tkinter e mainloop, ma sarebbe consumatore più memoria rispetto alla soluzione sopra, e si richiede di impostare una qualche forma di interprocesso comunicazione se si desidera che i processi separati condividano le informazioni.

+0

Ora sto ottenendo una nuova radice con 'tk.Tk()' ma non chiamando 'mainloop()' di nuovo - questo sembra funzionare pur essendo molto più semplice - qualche idea del perché potrebbe essere? Si potrebbe pensare che 'Tk()' sarebbe un singleton che restituisce lo stesso master, ma la creazione di widget su di esso non sembra influire sulla prima finestra. –

+0

Vedere la mia modifica alla domanda originale - Intendevo il processo non thread. –

+1

Non sono abbastanza sicuro di aver capito la tua domanda. C'è un modo molto più semplice di quello che mostro sopra - basta usare Toplevels e chiamare 'root.withdraw()' - ma poi puoi chiudere tutti i tuoi Toplevel e il programma continuerà a funzionare in background. Accumulerai i processi zombi in questo modo. Lo scopo della trappola sopra è di far terminare il programma quando l'ultimo Toplevel è chiuso. Se non sto rispondendo alla tua domanda, per favore pubblica il tuo codice. – unutbu

Problemi correlati