Como lidar com o evento de fechamento da janela (usuário clicando no botão 'X') em um programa Python Tkinter?
131
O Tkinter suporta um mecanismo chamado manipuladores de protocolo . Aqui, o termo protocolo refere-se à interação entre o aplicativo e o gerenciador de janelas. O protocolo mais usado é chamadoWM_DELETE_WINDOW
e é usado para definir o que acontece quando o usuário fecha explicitamente uma janela usando o gerenciador de janelas.
Você pode usar o protocol
método para instalar um manipulador para este protocolo (o widget deve ser um Tk
ou Toplevel
widget):
Aqui você tem um exemplo concreto:
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
não havia uma caixa de mensagens do submódulo. Eu useiimport tkMessageBox as messagebox
Matt mostrou uma modificação clássica do botão Fechar.
A outra é fazer com que o botão fechar minimize a janela.
Você pode reproduzir esse comportamento fazendo com que o método iconify
seja o segundo argumento do método de protocolo .
Aqui está um exemplo de trabalho, testado no Windows 7 e 10:
Neste exemplo, damos ao usuário duas novas opções de saída:
o arquivo clássico → Sair e também o Escbotão.
fonte
Dependendo da atividade do Tkinter, e especialmente ao usar o Tkinter.after, interromper essa atividade com
destroy()
- mesmo usando o protocolo (), um botão etc. - perturbará essa atividade (erro "durante a execução") em vez de apenas encerrá-la . A melhor solução em quase todos os casos é usar uma bandeira. Aqui está um exemplo simples e bobo de como usá-lo (embora eu esteja certo de que a maioria de vocês não precisa!)Isso finaliza bem a atividade gráfica. Você só precisa verificar
running
no (s) local (is) certo (s).fonte
Gostaria de agradecer a resposta de Apostolos por trazer isso à minha atenção. Aqui está um exemplo muito mais detalhado do Python 3 no ano de 2019, com uma descrição e um código de exemplo mais claros.
Cuidado com o fato de que
destroy()
(ou não ter um manipulador de fechamento de janela personalizado) destruirá a janela e todos os seus retornos de chamada em execução instantaneamente quando o usuário a fechar.Isso pode ser ruim para você, dependendo da atividade atual do Tkinter e, principalmente, ao usar
tkinter.after
(retornos de chamada periódicos). Você pode estar usando um retorno de chamada que processa alguns dados e grava no disco ... nesse caso, obviamente você deseja que a gravação dos dados termine sem ser interrompida abruptamente.A melhor solução para isso é usar uma bandeira. Portanto, quando o usuário solicitar o fechamento da janela, marque-o como um sinalizador e reaja a ele.
(Nota: eu normalmente projeto GUIs como classes bem encapsuladas e segmentos de trabalho separados, e definitivamente não uso "global" (eu uso variáveis de instância de classe), mas isso deve ser um exemplo simples e simples para demonstrar como Tk mata abruptamente seus retornos de chamada periódicos quando o usuário fecha a janela ...)
Esse código mostra que o
WM_DELETE_WINDOW
manipulador é executado mesmo enquanto nossoperiodic_call()
está ocupado no meio do trabalho / loops!Usamos alguns
.after()
valores bastante exagerados : 500 milissegundos. Isso serve apenas para facilitar a visualização da diferença entre o fechamento enquanto a chamada periódica está ocupada ou não ... Se você fechar enquanto os números estiverem sendo atualizados, verá queWM_DELETE_WINDOW
aconteceu enquanto a ligação periódica "foi processamento ocupado: True ". Se você fechar enquanto os números estiverem pausados (o que significa que o retorno periódico de chamada não está sendo processado naquele momento), você verá que o fechamento ocorreu enquanto "não está ocupado".No uso no mundo real, seu
.after()
usaria algo como 30 a 100 milissegundos, para ter uma GUI responsiva. Esta é apenas uma demonstração para ajudá-lo a entender como se proteger do comportamento padrão de Tk "interrompe instantaneamente todo o trabalho ao fechar" o comportamento.Em resumo: faça com que o
WM_DELETE_WINDOW
manipulador defina um sinalizador e verifique periodicamente e manualmente.destroy()
a janela quando estiver seguro (quando seu aplicativo terminar com todo o trabalho).PS: Você também pode usar
WM_DELETE_WINDOW
para perguntar ao usuário se eles realmente querem fechar a janela; e se eles responderem não, você não definirá a bandeira. É muito simples. Você apenas mostra uma caixa de mensagens na suaWM_DELETE_WINDOW
e define a sinalização com base na resposta do usuário.fonte
Experimente a versão simples:
Ou se você deseja adicionar mais comandos:
fonte
fonte