web-dev-qa-db-fra.com

Quand dois-je appeler mainloop dans une application Tkinter?

Chaque tutoriel tkinter que j'ai vu affirme que tkinter.mainloop doit être appelé pour que les fenêtres soient dessinées et les événements traités, et ils appellent toujours cette fonction, même dans les programmes Hello World. Cependant, lorsque je les essaie dans le shell interactif, les fenêtres sont dessinées correctement sans avoir à appeler la boucle principale. Cet exemple d'incorporation de graphiques matplotlib dans tkinter produit une application relativement complexe, avec des boutons pour le panoramique, le zoom et le redimensionnement d'un tracé dans une fenêtre tkinter, et encore une fois, tout cela fonctionne si vous supprimez l'appel à mainloop et exécutez le code dans le shell interactif. Bien sûr, si j'exécute le script (avec la boucle principale supprimée) en dehors du shell interactif, le programme se termine trop rapidement pour voir ce qui se passe, mais si j'ajoute un appel à input pour maintenir le programme ouvert, tout fonctionne correctement ( J'exécute python 3.2.2 sur linux).

Alors, que fait exactement mainloop, et quand est-il nécessaire de l'appeler?

EDIT: Pour clarifier, si j'ouvre le terminal GNOME et tape

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

une fenêtre apparaît immédiatement sans avoir à appeler mainloop, et la fonctionnalité tkinter plus complexe semble également fonctionner (par exemple, en ajoutant des boutons à la fenêtre). Dans IDLE, un appel à mainloop est nécessaire. J'ai cru comprendre que rien ne devait être dessiné, et aucun événement ne devait être traité, jusqu'à ce que la boucle principale soit appelée.

40
James

La réponse à votre question principale est que vous devez appeler mainloop une seule et unique fois, lorsque vous êtes prêt à exécuter votre application.

mainloop n'est pas beaucoup plus qu'une boucle infinie qui ressemble à peu près à cela (ce ne sont pas les noms réels des méthodes, les noms servent simplement à illustrer le point):

while True:
    event=wait_for_event()
    event.process()
    if main_window_has_been_destroyed(): 
        break

Dans ce contexte, "événement" signifie à la fois les interactions de l'utilisateur (clics de souris, pressions sur les touches, etc.) et les demandes de la boîte à outils ou du gestionnaire de système d'exploitation/fenêtre pour dessiner ou redessiner un widget. Si cette boucle n'est pas en cours d'exécution, les événements ne sont pas traités. Si les événements ne sont pas traités, rien n'apparaîtra à l'écran et votre programme se fermera probablement à moins que vous ayez votre propre boucle infinie en cours d'exécution.

Alors, pourquoi n'avez-vous pas besoin d'appeler cela de manière interactive? C'est juste une commodité, car sinon il serait impossible d'entrer des commandes une fois que vous appelez mainloop puisque mainloop s'exécute jusqu'à ce que la fenêtre principale soit détruite.

46
Bryan Oakley

Comparez un programme avec une interface graphique interactive à un programme qui calcule le centième nombre de Fibonacci. Tout ce dernier programme doit passer par une série d'étapes dans l'ordre, de haut en bas. L'ensemble des étapes et leur séquence peuvent être connus à l'avance, et ils resteront constants quel que soit le nombre de fois que vous exécutez le programme.

Mais le programme GUI est différent: à tout moment, il doit être capable de gérer toutes sortes d'événements et d'interactions différents. Cette exigence est souvent implémentée à l'aide d'une construction de programmation appelée boucle d'événements. Une boucle d'événements est la structure de contrôle centrale d'un programme. Il attend qu'un événement se produise, puis envoie le gestionnaire approprié.

Vous n'avez pas mentionné le Shell interactif que vous utilisez, mais je suppose que c'est IDLE. IDLE lui-même est un programme Tkinter, et il a déjà une boucle d'événements en cours. Il est donc possible que le code Tkinter que vous saisissez dans le shell soit lié à la boucle d'événements IDLE.

7
Ori