Jak obsłużyć zdarzenie zamknięcia okna (użytkownik kliknie przycisk „X”) w programie Python Tkinter?
130
Tkinter obsługuje mechanizm zwany programami obsługi protokołów . Tutaj termin protokół odnosi się do interakcji między aplikacją a menedżerem okien. Najczęściej używany protokół jest nazywany WM_DELETE_WINDOW
i służy do definiowania tego, co się dzieje, gdy użytkownik jawnie zamyka okno za pomocą menedżera okien.
Możesz użyć tej protocol
metody, aby zainstalować program obsługi dla tego protokołu (widget musi być widgetem Tk
lub Toplevel
):
Tutaj masz konkretny przykład:
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
nie miałem pola wiadomości podmodułu. Użyłemimport tkMessageBox as messagebox
Matt pokazał jedną klasyczną modyfikację przycisku zamykającego.
Drugi to przycisk zamykania, który minimalizuje okno.
Możesz odtworzyć to zachowanie, mając metodę iconify
jako drugi argument metody protokołu .
Oto działający przykład, przetestowany na Windows 7 i 10:
W tym przykładzie dajemy użytkownikowi dwie nowe opcje wyjścia:
klasyczną Plik → Zakończ, a także Escprzycisk.
źródło
W zależności od aktywności Tkinter, a zwłaszcza podczas korzystania z Tkinter.after, zatrzymanie tej czynności za pomocą
destroy()
- nawet przy użyciu protokołu (), przycisku itp. - zakłóci tę czynność (błąd „podczas wykonywania”), a nie po prostu ją zakończy . Prawie w każdym przypadku najlepszym rozwiązaniem jest użycie flagi. Oto prosty, głupiutki przykład, jak go używać (chociaż jestem pewien, że większość z Was go nie potrzebuje! :)To ładnie kończy aktywność graficzną. Musisz tylko sprawdzić
running
we właściwym miejscu (miejscach).źródło
Chciałbym podziękować odpowiedzi Apostolos za zwrócenie mi na to uwagi. Oto znacznie bardziej szczegółowy przykład dla Pythona 3 w roku 2019, z jaśniejszym opisem i przykładowym kodem.
Uważaj na fakt, że
destroy()
(lub w ogóle brak niestandardowego modułu obsługi zamykania okna) zniszczy okno i wszystkie jego uruchomione wywołania zwrotne natychmiast po zamknięciu go przez użytkownika.Może to być dla Ciebie złe, w zależności od Twojej bieżącej aktywności Tkinter, a zwłaszcza podczas korzystania z
tkinter.after
(okresowe wywołania zwrotne). Być może używasz wywołania zwrotnego, które przetwarza niektóre dane i zapisuje na dysku ... w takim przypadku chcesz oczywiście zakończyć zapisywanie danych bez nagłego zabicia.Najlepszym rozwiązaniem jest użycie flagi. Więc kiedy użytkownik zażąda zamknięcia okna, zaznaczasz to jako flagę, a następnie reagujesz na to.
(Uwaga: zwykle projektuję GUI jako ładnie zamknięte klasy i oddzielne wątki robocze i zdecydowanie nie używam „globalnego” (zamiast tego używam zmiennych instancji klas), ale ma to być prosty, okrojony przykład pokazujący jak Tk nagle zabija twoje okresowe wywołania zwrotne, gdy użytkownik zamyka okno ...)
Ten kod pokaże ci, że program
WM_DELETE_WINDOW
obsługi działa nawet wtedy, gdy nasz niestandardowyperiodic_call()
jest zajęty w środku pracy / pętli!Używamy dość przesadzonych
.after()
wartości: 500 milisekund. Ma to tylko na celu ułatwienie Ci dostrzeżenia różnicy między zamknięciem, gdy okresowa rozmowa jest zajęta, czy nie… Jeśli zamkniesz konto podczas aktualizacji numerów, zobaczysz, żeWM_DELETE_WINDOW
stało się to, gdy Twoje połączenie okresowe było zajęte przetwarzanie: prawda ”. Jeśli zamkniesz, gdy numery są wstrzymane (co oznacza, że okresowe oddzwanianie nie jest w tej chwili przetwarzane), zobaczysz, że zamknięcie nastąpiło, gdy nie jest zajęty.W prawdziwym świecie
.after()
potrzebowałbyś około 30-100 milisekund, aby mieć responsywny GUI. To tylko demonstracja, która pomoże ci zrozumieć, jak chronić się przed domyślnym zachowaniem Tk „natychmiast przerywaj całą pracę przy zamykaniu”.Podsumowując: spraw, aby program
WM_DELETE_WINDOW
obsługi ustawił flagę, a następnie okresowo sprawdzaj tę flagę i ręcznie sprawdzaj.destroy()
okno, gdy jest to bezpieczne (gdy aplikacja jest zakończona z całą pracą).PS: Możesz również użyć,
WM_DELETE_WINDOW
aby zapytać użytkownika, czy NAPRAWDĘ chce zamknąć okno; a jeśli odpowiedzą „nie”, nie ustawiasz flagi. To jest bardzo proste. Po prostu pokazujesz skrzynkę wiadomości w swoimWM_DELETE_WINDOW
i ustawiasz flagę na podstawie odpowiedzi użytkownika.źródło
Wypróbuj prostą wersję:
Lub jeśli chcesz dodać więcej poleceń:
źródło
źródło