Kiedy muszę wywołać mainloop w aplikacji Tkinter?

Każdy tutorial tkinter, który widziałem twierdzi, że tkinter.mainloop musi być wywołany, aby windows był rysowany i zdarzenia były przetwarzane, i zawsze wywołują tę funkcję, nawet w programach hello world. Jednak, gdy wypróbuję je w interaktywnej powłoce, okna są rysowane poprawnie bez konieczności wywoływania mainloop. Ten przykład osadzania Grafiki matplotlib w tkinter tworzy stosunkowo złożoną aplikację, z przyciskami do panoramowania, powiększania i zmiany rozmiaru wykresu w tkinter okno, i znowu, to wszystko działa, jeśli usuniesz wywołanie do mainloop i uruchomić kod w powłoce interaktywnej. Oczywiście, jeśli uruchamiam skrypt (z usuniętym mainloop) poza interaktywną powłoką, Program kończy się zbyt szybko, aby zobaczyć, co się stanie, ale jeśli dodam wywołanie input, aby utrzymać program otwarty, wszystko działa poprawnie (uruchamiam Pythona 3.2.2 na Linuksie).

Więc co dokładnie robi mainloop i kiedy trzeba go nazwać?

Edytuj: Dla wyjaśnienia, jeśli otworzę Terminal GNOME i typ

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

Okno pojawia się natychmiast bez konieczności wywoływania mainloop, a bardziej złożona funkcjonalność tkinter wydaje się działać również (na przykład dodawanie przycisków do okna). W trybie bezczynności konieczne jest wywołanie mainloop. Zrozumiałem, że nic nie powinno być rysowane i żadne zdarzenia nie powinny być przetwarzane, dopóki nie zostanie wywołane mainloop.

Author: nbro, 2011-12-30

4 answers

Odpowiedź na twoje główne pytanie brzmi: musisz zadzwonić do mainloop raz i tylko raz, gdy będziesz gotowy do uruchomienia aplikacji.

mainloop to niewiele więcej niż nieskończona pętla, która wygląda mniej więcej tak (nie są to rzeczywiste nazwy metod, nazwy służą jedynie do zilustrowania punktu): {]}

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

W tym kontekście "zdarzenie" oznacza zarówno interakcje użytkownika (kliknięcia myszką, naciśnięcia klawiszy itp.), jak i żądania z zestawu narzędzi lub Menedżera systemu operacyjnego/okien w celu narysowania lub przerysowania widget. Jeśli ta pętla nie działa, zdarzenia nie są przetwarzane. Jeśli zdarzenia nie zostaną przetworzone, nic nie pojawi się na ekranie, a twój program prawdopodobnie zakończy działanie, chyba że masz własną nieskończoną pętlę.

Więc dlaczego nie musisz tego wywoływać interaktywnie? To tylko wygoda, ponieważ w przeciwnym razie nie byłoby możliwe wprowadzenie żadnych poleceń po wywołaniu mainloop, Ponieważ mainloop działa, dopóki główne okno nie zostanie zniszczone.
 40
Author: Bryan Oakley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-25 11:18:33

Porównaj program z interaktywnym GUI z programem, który oblicza setną liczbę Fibonacciego. Cały ten ostatni program musi przejść przez szereg kroków w kolejności, od góry do dołu. Zestaw kroków i ich sekwencjonowanie może być znane z góry i pozostanie stały bez względu na to, ile razy uruchomisz program.

Ale program GUI jest inny: w danym momencie musi być w stanie obsłużyć różnego rodzaju zdarzenia i interakcje. Wymóg ten jest często realizowany przy użyciu konstrukcji programistycznej zwanej pętlą zdarzeń. Pętla zdarzeń jest centralną strukturą sterującą programu. Oczekuje na zdarzenie, a następnie wysyła odpowiedni handler.

Nie wspomniałeś, której interaktywnej powłoki używasz, ale zgaduję, że jest bezczynna. IDLE sam w sobie jest programem Tkinter i ma już uruchomioną pętlę zdarzeń. Więc prawdopodobnie Kod Tkinter, który wpisujesz do powłoki, zostanie powiązany z pętlą zdarzeń IDLE.

 7
Author: Ori,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-30 21:29:19

Zdecydowałem, że zamiast trzymać wywołanie bezpośrednio do mainloop gdziekolwiek w moim skrypcie, dodam je jako część atexit - to znaczy, gdy interpreter Pythona zdecyduje, że nadszedł czas, aby rozpocząć zamykanie, wejdzie do mainloop Tk. To uniemożliwia mu zakończenie sekwencji wyłączania, dopóki użytkownik nie powie TK, aby zakończył pracę (np. za pomocą polecenia-Q na komputerze Mac lub klikając na czerwony X w systemie Windows.)

from Tkinter import Tk
root = Tk()

import atexit
atexit.register(root.mainloop)

Wydaje się, że nie ma potrzeby wywoływania {[2] } z polecenia systemowego Kolejka Interpreter Pythona będzie nadal działał bez niego, ponieważ czeka na dalsze dane od Ciebie (dopóki nie uruchomisz exit()).

 -2
Author: ArtOfWarfare,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-10 20:11:48

Następująco:

from tkinter import *

tk = Tk()
canvas = Canvas(tk, width=500, height=500)
canvas.pack()
canvas.create_line(0, 0, 500, 500)

mainloop()
 -3
Author: Balázs Ortutay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-11 13:48:16