¿Cómo manejo el evento de cierre de ventana (el usuario hace clic en el botón 'X') en un programa Python Tkinter?
131
Tkinter admite un mecanismo llamado controladores de protocolo . Aquí, el término protocolo se refiere a la interacción entre la aplicación y el administrador de ventanas. Se llama al protocolo más utilizado WM_DELETE_WINDOW
y se utiliza para definir qué sucede cuando el usuario cierra explícitamente una ventana utilizando el administrador de ventanas.
Puede usar el protocol
método para instalar un controlador para este protocolo (el widget debe ser un widget Tk
o Toplevel
):
Aquí tienes un ejemplo concreto:
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()
def on_closing():
if messagebox.askokcancel("Quit", "Do you want to quit?"):
root.destroy()
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()
Tkinter
no tenía un cuadro de mensaje de submódulo. Yo solíaimport tkMessageBox as messagebox
Matt ha mostrado una modificación clásica del botón de cierre.
El otro es hacer que el botón de cerrar minimice la ventana.
Puede reproducir este comportamiento haciendo que el método iconify
sea el segundo argumento del método de protocolo .
Aquí hay un ejemplo de trabajo, probado en Windows 7 y 10:
En este ejemplo, le damos al usuario dos nuevas opciones de salida:
el clásico Archivo → Salir, y también el Escbotón.
fuente
Dependiendo de la actividad de Tkinter, y especialmente cuando se usa Tkinter. Después, detener esta actividad con
destroy()
- incluso usando el protocolo (), un botón, etc. - perturbará esta actividad (error "al ejecutar") en lugar de simplemente terminarla . La mejor solución en casi todos los casos es usar una bandera. Aquí hay un ejemplo simple y tonto de cómo usarlo (¡aunque estoy seguro de que la mayoría de ustedes no lo necesita! :)Esto termina la actividad gráfica muy bien. Solo necesita marcar
running
en los lugares correctos.fuente
Me gustaría agradecer la respuesta de Apostolos por llamar mi atención. Aquí hay un ejemplo mucho más detallado para Python 3 en el año 2019, con una descripción más clara y un código de ejemplo.
Tenga en cuenta el hecho de que
destroy()
(o no tener un controlador de cierre de ventana personalizado) destruirá la ventana y todas sus devoluciones de llamada en ejecución instantáneamente cuando el usuario la cierre.Esto puede ser malo para usted, dependiendo de su actividad actual de Tkinter, y especialmente cuando usa
tkinter.after
(devoluciones de llamada periódicas). Es posible que esté utilizando una devolución de llamada que procesa algunos datos y escribe en el disco ... en ese caso, obviamente desea que finalice la escritura de datos sin que se elimine abruptamente.La mejor solución para eso es usar una bandera. Entonces, cuando el usuario solicita el cierre de la ventana, lo marca como un indicador y luego reacciona a él.
(Nota: normalmente diseño interfaces gráficas de usuario como clases bien encapsuladas y subprocesos de trabajo separados, y definitivamente no uso "global" (en su lugar utilizo variables de instancia de clase), pero esto pretende ser un ejemplo simple y simplificado para demostrar cómo Tk mata abruptamente sus devoluciones de llamadas periódicas cuando el usuario cierra la ventana ...)
¡Este código le mostrará que el
WM_DELETE_WINDOW
controlador se ejecuta incluso mientras nuestra costumbreperiodic_call()
está ocupada en medio del trabajo / bucles!Usamos algunos
.after()
valores bastante exagerados : 500 milisegundos. Esto solo tiene la intención de que sea muy fácil para usted ver la diferencia entre cerrar mientras la llamada periódica está ocupada, o no ... Si cierra mientras se actualizan los números, verá queWM_DELETE_WINDOW
sucedió mientras su llamada periódica "estaba procesamiento ocupado: verdadero ". Si cierra mientras los números están en pausa (lo que significa que la devolución de llamada periódica no se está procesando en ese momento), verá que el cierre se produjo mientras "no está ocupado".En el uso en el mundo real,
.after()
usaría algo así como 30-100 milisegundos, para tener una GUI receptiva. Esto es solo una demostración para ayudarlo a comprender cómo protegerse contra el comportamiento predeterminado de Tk de "interrumpir instantáneamente todo el trabajo al cerrar".En resumen: haga que el
WM_DELETE_WINDOW
controlador establezca una bandera y luego verifique esa bandera periódicamente y manualmente en.destroy()
la ventana cuando sea seguro (cuando su aplicación haya terminado con todo el trabajo).PD: También puede usar
WM_DELETE_WINDOW
para preguntar al usuario si REALMENTE desea cerrar la ventana; y si responden que no, no estableces la bandera. Es muy simple. Simplemente muestra un cuadro de mensaje en suWM_DELETE_WINDOW
y establece el indicador en función de la respuesta del usuario.fuente
Prueba la versión simple:
O si desea agregar más comandos:
fuente
fuente