tkinter
Finestre multiple (widget TopLevel)
Ricerca…
Differenza tra Tk e Toplevel
Tk
è la radice assoluta dell'applicazione, è il primo widget che deve essere istanziato e la GUI si spegne quando viene distrutta.
Toplevel
è una finestra dell'applicazione, chiudendo la finestra si distruggeranno tutti i widget figli posizionati su quella finestra {1} ma non si spegnerà il programma.
try:
import tkinter as tk #python3
except ImportError:
import Tkinter as tk #python2
#root application, can only have one of these.
root = tk.Tk()
#put a label in the root to identify the window.
label1 = tk.Label(root, text="""this is root
closing this window will shut down app""")
label1.pack()
#you can make as many Toplevels as you like
extra_window = tk.Toplevel(root)
label2 = tk.Label(extra_window, text="""this is extra_window
closing this will not affect root""")
label2.pack()
root.mainloop()
Se il tuo programma python rappresenta solo una singola applicazione (cosa che quasi sempre Toplevel
) dovresti avere una sola istanza di Tk
, ma puoi creare Toplevel
finestre Toplevel
che desideri.
try:
import tkinter as tk #python3
except ImportError:
import Tkinter as tk #python2
def generate_new_window():
window = tk.Toplevel()
label = tk.Label(window, text="a generic Toplevel window")
label.pack()
root = tk.Tk()
spawn_window_button = tk.Button(root,
text="make a new window!",
command=generate_new_window)
spawn_window_button.pack()
root.mainloop()
{1}: se un Toplevel ( A = Toplevel(root)
) è il genitore di un altro Toplevel ( B = Toplevel(A)
), la finestra di chiusura A chiuderà anche la finestra B.
organizzare la pila di finestre (il metodo .lift)
Il caso più semplice per sollevare una finestra particolare sopra gli altri, basta chiamare il metodo .lift()
su quella finestra ( Toplevel
o Tk
)
import tkinter as tk #import Tkinter as tk #change to commented for python2
root = tk.Tk()
for i in range(4):
#make a window with a label
window = tk.Toplevel(root)
label = tk.Label(window,text="window {}".format(i))
label.pack()
#add a button to root to lift that window
button = tk.Button(root, text = "lift window {}".format(i), command=window.lift)
button.grid(row=i)
root.mainloop()
Tuttavia, se quella finestra viene distrutta cercando di sollevarla, si genera un errore come questo:
Exception in Tkinter callback
Traceback (most recent call last):
File "/.../tkinter/__init__.py", line 1549, in __call__
return self.func(*args)
File "/.../tkinter/__init__.py", line 785, in tkraise
self.tk.call('raise', self._w, aboveThis)
_tkinter.TclError: bad window path name ".4385637096"
Spesso, quando proviamo a mettere una finestra particolare davanti all'utente, ma è stata chiusa, una buona alternativa è ricreare quella finestra:
import tkinter as tk #import Tkinter as tk #change to commented for python2
dialog_window = None
def create_dialog():
"""creates the dialog window
** do not call if dialog_window is already open, this will
create a duplicate without handling the other
if you are unsure if it already exists or not use show_dialog()"""
global dialog_window
dialog_window = tk.Toplevel(root)
label1 = tk.Label(dialog_window,text="this is the dialog window")
label1.pack()
#put other widgets
dialog_window.lift() #ensure it appears above all others, probably will do this anyway
def show_dialog():
"""lifts the dialog_window if it exists or creates a new one otherwise"""
#this can be refactored to only have one call to create_dialog()
#but sometimes extra code will be wanted the first time it is created
if dialog_window is None:
create_dialog()
return
try:
dialog_window.lift()
except tk.TclError:
#window was closed, create a new one.
create_dialog()
root = tk.Tk()
dialog_button = tk.Button(root,
text="show dialog_window",
command=show_dialog)
dialog_button.pack()
root.mainloop()
In questo modo la funzione show_dialog
mostrerà alla finestra di dialogo se esiste o meno, inoltre si noti che è possibile chiamare .winfo_exists()
per verificare se esiste prima di provare a sollevare la finestra invece di avvolgerla in una try:except
.
Esiste anche il metodo .lower()
che funziona allo stesso modo del metodo .lift()
, ad eccezione dell'abbassare la finestra nello stack:
import tkinter as tk #import Tkinter as tk #change to commented for python2
root = tk.Tk()
root.title("ROOT")
extra = tk.Toplevel()
label = tk.Label(extra, text="extra window")
label.pack()
lower_button = tk.Button(root,
text="lower this window",
command=root.lower)
lower_button.pack()
root.mainloop()
Noterai che si abbassa anche al di sotto di altre applicazioni, per abbassare solo al di sotto di una certa finestra puoi passarlo al metodo .lower()
, allo stesso modo questo può essere fatto anche con il metodo .lift()
per sollevare solo una finestra sopra un'altra uno.