python - standard - ¿Cuándo debo llamar a mainloop en una aplicación Tkinter?
standard library tkinter python (4)
Cada tutorial de tkinter que he visto afirma que debe llamarse a tkinter.mainloop
que se tkinter.mainloop
ventanas y que se procesen los eventos, y siempre llaman a esta función, incluso en los programas hello world. Sin embargo, cuando pruebo esto en el shell interactivo, las ventanas se dibujan correctamente sin tener que llamar a mainloop. Este ejemplo de incrustación de gráficos matplotlib en tkinter produce una aplicación relativamente compleja, con botones para panoramizar, ampliar y cambiar el tamaño de un gráfico dentro de una ventana tkinter, y de nuevo, todo funciona si elimina la llamada a mainloop y ejecuta el código en el shell interactivo . Por supuesto, si ejecuto el script (con mainloop eliminado) fuera del shell interactivo, el programa finaliza demasiado rápido para ver qué sucede, pero si agrego una llamada para input
para mantener el programa abierto, todo funciona correctamente (estoy ejecutando python 3.2.2 en Linux).
Entonces, ¿qué hace exactamente mainloop, y cuándo es necesario llamarlo?
EDITAR: Para aclarar, si abro el terminal GNOME y escribo
$python3
>>> import tkinter
>>> root = tkinter.Tk()
inmediatamente aparece una ventana sin tener que llamar a mainloop, y la funcionalidad de tkinter más compleja parece funcionar también (por ejemplo, agregando botones a la ventana). En IDLE, se necesita una llamada a mainloop. Tenía entendido que no se debería extraer nada, y no se deberían procesar eventos hasta que se llame a mainloop.
Como sigue:
from tkinter import *
tk = Tk()
canvas = Canvas(tk, width=500, height=500)
canvas.pack()
canvas.create_line(0, 0, 500, 500)
mainloop()
Compare un programa con una GUI interactiva con un programa que calcule el centésimo número de Fibonacci. Todo el último programa tiene que pasar por una serie de pasos en orden, de arriba abajo. El conjunto de pasos y su secuencia se pueden conocer de antemano, y se mantendrá constante sin importar cuántas veces ejecutes el programa.
Pero el programa GUI es diferente: en un momento dado, tiene que ser capaz de manejar todo tipo de diferentes tipos de eventos e interacciones. Este requisito a menudo se implementa utilizando una construcción de programación llamada un ciclo de eventos. Un bucle de evento es la estructura de control central de un programa. Espera a que ocurra un evento y luego envía el controlador apropiado.
No mencionaste qué caparazón interactivo estás utilizando, pero supongo que es INACTIVO. IDLE en sí mismo es un programa Tkinter, y ya tiene un bucle de eventos. Así que posiblemente el código de Tkinter que estás escribiendo en el shell esté vinculado al bucle de eventos de IDLE.
Decidí que, en lugar de hacer una llamada directamente a mainloop en cualquier lugar de mi script, solo lo atexit
como parte de atexit
, es decir, cuando el intérprete de Python decida que es hora de comenzar a cerrar, entrará en Tk''s bucle principal. Esto luego evita que finalice la secuencia de apagado hasta que el usuario realmente le pida a Tk que se cierre (IE, con el comando-Q en una Mac, o haciendo clic en la X roja en Windows).
from Tkinter import Tk
root = Tk()
import atexit
atexit.register(root.mainloop)
Parece que no es necesario llamar a mainloop
desde una línea de comando del sistema. El intérprete de Python continuará ejecutándose sin él, porque está esperando su entrada (hasta que ejecute exit()
).
La respuesta a su pregunta principal es: debe llamar a mainloop una vez y solo una vez, cuando esté listo para que se ejecute su aplicación.
mainloop
no es mucho más que un bucle infinito que se parece más o menos a esto (esos no son los nombres reales de los métodos, los nombres simplemente sirven para ilustrar el punto):
while True:
event=wait_for_event()
event.process()
if main_window_has_been_destroyed():
break
En este contexto, "evento" significa tanto las interacciones del usuario (clics del mouse, pulsaciones de teclas, etc.) como las solicitudes del kit de herramientas o del administrador del sistema operativo / ventanas para dibujar o volver a dibujar un widget. Si ese bucle no se está ejecutando, los eventos no se procesan. Si los eventos no se procesan, nada aparecerá en la pantalla y tu programa probablemente salga a menos que tengas tu propio bucle infinito en ejecución.
Entonces, ¿por qué no necesitas llamar esto de manera interactiva? Eso es solo una conveniencia, porque de lo contrario sería imposible ingresar cualquier comando una vez que llame a mainloop
ya que mainloop
ejecuta hasta que se destruye la ventana principal.