tkinter
Varias ventanas (widgets TopLevel)
Buscar..
Diferencia entre Tk y Toplevel
Tk
es la raíz absoluta de la aplicación, es el primer widget que debe crearse y la GUI se cerrará cuando se destruya.
Toplevel
es una ventana en la aplicación, cerrar la ventana destruirá todos los widgets secundarios colocados en esa ventana {1} pero no cerrará el programa.
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()
Si su programa de Python solo representa una aplicación única (que casi siempre lo hará), entonces debería tener solo una instancia de Tk
, pero puede crear tantas ventanas de Toplevel
como desee.
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}: si un Toplevel ( A = Toplevel(root)
) es el padre de otro Toplevel ( B = Toplevel(A)
), al cerrar la ventana A también se cerrará la ventana B.
ordenando la pila de ventanas (el método .lift)
El caso más básico para levantar una ventana en particular sobre las otras, simplemente llame al método .lift()
en esa ventana (ya sea 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()
Sin embargo, si esa ventana se destruye al intentar levantarla, se generará un error como este:
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"
A menudo, cuando intentamos colocar una ventana en particular frente al usuario, pero se cerró, una buena alternativa es recrear esa ventana:
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()
De esta manera, la función show_dialog
mostrará la ventana de diálogo si existe o no, también tenga en cuenta que puede llamar a .winfo_exists()
para verificar si existe antes de intentar levantar la ventana en lugar de envolverla en un try:except
.
También existe el método .lower()
que funciona de la misma manera que el método .lift()
, excepto que se baja la ventana en la pila:
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()
Notará que baja incluso por debajo de otras aplicaciones, para bajar solo por debajo de una determinada ventana, puede pasarlo al método .lower()
, de manera similar, esto también se puede hacer con el método .lift()
para elevar una ventana por encima de otra. uno.