¿Cuándo necesito llamar a mainloop en una aplicación Tkinter?

En cada tutorial de tkinter he visto afirmaciones de que se debe llamar a tkinter.mainloop que se tkinter.mainloop ventanas y que se procesen eventos, y siempre llaman a esta función, incluso en los progtwigs de hello world. Sin embargo, cuando pruebo estos en el shell interactivo, las ventanas se dibujan correctamente sin tener que llamar a mainloop. Este ejemplo de incrustación de gráficos de matplotlib en tkinter produce una aplicación relativamente compleja, con botones para encuadrar, ampliar y redimensionar una ttwig dentro de una ventana de tkinter, y todo esto 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 progtwig termina demasiado rápido para ver qué sucede, pero si agrego una llamada a la input para mantener el progtwig 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 de GNOME y escribo

 $python3 >>> import tkinter >>> root = tkinter.Tk() 

aparece una ventana inmediatamente sin tener que llamar a mainloop, y la funcionalidad tkinter más compleja parece funcionar también (por ejemplo, agregar botones a la ventana). En IDLE, es necesaria una llamada a mainloop. Entendí que no se debe dibujar nada, y que no se deben procesar eventos, hasta que se llame a mainloop.

La respuesta a su pregunta principal es que 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 aproximadamente 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 de ventanas / SO 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, no aparecerá nada en la pantalla y es probable que su progtwig se cierre a menos que tenga su propio bucle infinito en ejecución.

Entonces, ¿por qué no necesitas llamar a esto interactivamente? Eso es solo una conveniencia, porque de lo contrario sería imposible ingresar cualquier comando una vez que llame a mainloop desde que mainloop ejecute hasta que se destruya la ventana principal.

Compare un progtwig con una GUI interactiva con un progtwig que calcula el centésimo número de Fibonacci. Todo el último progtwig tiene que pasar por una serie de pasos en orden, de arriba abajo. El conjunto de pasos y su secuencia se puede conocer de antemano, y se mantendrá constante sin importar cuántas veces ejecute el progtwig.

Pero el progtwig GUI es diferente: en cualquier momento, tiene que ser capaz de manejar todo tipo de eventos e interacciones. Este requisito se implementa a menudo utilizando una construcción de progtwigción llamada un bucle de eventos. Un bucle de eventos es la estructura de control central de un progtwig. Espera a que ocurra un evento y, a continuación, envía el controlador adecuado.

No mencionaste qué shell interactivo estás usando, pero supongo que es IDLE. IDLE en sí es un progtwig Tkinter, y ya tiene un bucle de eventos en marcha. Así que posiblemente el código Tkinter que está escribiendo en el shell se está vinculando al bucle de eventos de IDLE.

Como sigue:

 from tkinter import * tk = Tk() canvas = Canvas(tk, width=500, height=500) canvas.pack() canvas.create_line(0, 0, 500, 500) mainloop() 

Decidí que, en lugar de enviar 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 decide que es hora de comenzar a cerrar, va a ingresar a Tk’s bucle principal. Esto evita que finalice la secuencia de apagado hasta que el usuario realmente le diga a Tk que salga (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 hay necesidad de llamar a mainloop desde una línea de comandos del sistema. El intérprete de Python continuará ejecutándose sin él, porque está esperando más información de usted (hasta que ejecute exit() ).