Python 如何处理Tkinter中的窗口关闭事件?

Python 如何处理Tkinter中的窗口关闭事件?,python,events,tkinter,window,Python,Events,Tkinter,Window,如何在Python Tkinter程序中处理窗口关闭事件(用户单击“X”按钮)?Tkinter支持一种称为的机制。这里,术语协议指的是应用程序和窗口管理器之间的交互。最常用的协议称为WM_DELETE_WINDOW,用于定义用户使用窗口管理器显式关闭窗口时发生的情况 您可以使用protocol方法安装此协议的处理程序(小部件必须是Tk或Toplevel小部件): 这里有一个具体的例子: import tkinter as tk from tkinter import messagebox ro

如何在Python Tkinter程序中处理窗口关闭事件(用户单击“X”按钮)?

Tkinter支持一种称为的机制。这里,术语协议指的是应用程序和窗口管理器之间的交互。最常用的协议称为
WM_DELETE_WINDOW
,用于定义用户使用窗口管理器显式关闭窗口时发生的情况

您可以使用
protocol
方法安装此协议的处理程序(小部件必须是
Tk
Toplevel
小部件):

这里有一个具体的例子:

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()

Matt展示了关闭按钮的一个经典修改。
另一个是让关闭按钮最小化窗口。
您可以通过使用方法来复制此行为
是该方法的第二个参数

下面是一个在Windows 7和10上测试的工作示例:

# Python 3
import tkinter
import tkinter.scrolledtext as scrolledtext

root = tkinter.Tk()
# make the top right close button minimize (iconify) the main window
root.protocol("WM_DELETE_WINDOW", root.iconify)
# make Esc exit the program
root.bind('<Escape>', lambda e: root.destroy())

# create a menu bar with an Exit command
menubar = tkinter.Menu(root)
filemenu = tkinter.Menu(menubar, tearoff=0)
filemenu.add_command(label="Exit", command=root.destroy)
menubar.add_cascade(label="File", menu=filemenu)
root.config(menu=menubar)

# create a Text widget with a Scrollbar attached
txt = scrolledtext.ScrolledText(root, undo=True)
txt['font'] = ('consolas', '12')
txt.pack(expand=True, fill='both')

root.mainloop()
#Python 3
进口tkinter
将tkinter.scrolledtext作为scrolledtext导入
root=tkinter.Tk()
#使右上角的关闭按钮最小化(图标化)主窗口
协议(“WM_删除_窗口”,root.iconify)
#使Esc退出程序
root.bind(“”,lambda e:root.destroy())
#使用Exit命令创建菜单栏
menubar=tkinter.Menu(根目录)
filemenu=tkinter.Menu(menubar,tearoff=0)
filemenu.add_命令(label=“Exit”,command=root.destroy)
menubar.add_级联(label=“File”,menu=filemenu)
root.config(menu=menubar)
#创建带有滚动条的文本小部件
txt=scrolledtext.scrolledtext(根,undo=True)
txt['font']=('consolas','12')
txt.pack(expand=True,fill='both')
root.mainloop()
在本例中,我们为用户提供了两个新的退出选项:

经典档案→ 退出,同时退出Esc按钮。

根据Tkinter活动,尤其是使用Tkinter时。之后,使用
destroy()
(即使使用协议()、按钮等)停止此活动将干扰此活动(“执行时”错误),而不仅仅是终止它。在几乎所有情况下,最好的解决方案都是使用标志。下面是一个简单而愚蠢的例子,说明了如何使用它(尽管我确信你们大多数人都不需要它!)

从Tkinter导入*
def关闭_窗口():
全球运行
运行=错误#在循环时关闭
打印(“窗口关闭”)
root=Tk()
协议(“WM_删除_窗口”,关闭_窗口)
cv=画布(根,宽度=200,高度=200)
简历包()
运行=真;
#这是一个无止境的循环,只有将“running”设置为“False”才能停止
运行时:
对于范围(200)内的i:
如果未运行:
打破
cv.创建椭圆(i,i,i+1,i+1)
root.update()

这很好地终止了图形活动。您只需在正确的位置检查
运行

尝试简单的版本:

import tkinter

window = Tk()

closebutton = Button(window, text='X', command=window.destroy)
closebutton.pack()

window.mainloop()

或者,如果要添加更多命令:

import tkinter

window = Tk()


def close():
    window.destroy()
    #More Functions


closebutton = Button(window, text='X', command=close)
closebutton.pack()

window.mainloop()
我要感谢Apostolos的回答让我注意到了这一点。下面是2019年Python3的一个更详细的示例,有更清晰的描述和示例代码


请注意,
destroy()
(或者根本没有自定义窗口关闭处理程序)会在用户关闭窗口时立即销毁窗口及其所有正在运行的回调。 这可能对您不利,具体取决于您当前的Tkinter活动,尤其是在使用
Tkinter.after
(定期回调)时。您可能正在使用回调来处理某些数据并写入磁盘。。。在这种情况下,您显然希望数据写入完成,而不会突然终止

最好的解决方案是使用标志。因此,当用户请求关闭窗口时,您将其标记为标志,然后对其作出反应

(注意:我通常将GUI设计为封装得很好的类和独立的工作线程,并且我肯定不使用“全局”(我使用类实例变量),但这是一个简单的、精简的示例,用于演示当用户关闭窗口时Tk如何突然终止定期回调…)

从tkinter导入*
导入时间
#尝试将此设置为False并查看打印的数字(1到10)
#在工作循环期间,如果在周期性调用
#工人正忙着工作(印刷)。它将突然结束这些数字,
#并杀死定期回调!这就是为什么你最应该设计的原因
#具有安全关闭回调的应用程序,如本演示中所述。
安全关闭=真
# ---------
忙处理=假
请求关闭\u=错误
def关闭_窗口():
请求全局关闭
请求关闭\u=真
打印(“用户请求的关闭时间:,time.time(),”正在忙处理:,正在忙处理)
root=Tk()
如果安全关闭:
协议(“WM_删除_窗口”,关闭_窗口)
lbl=标签(根)
lbl.pack()
def定期_调用():
全局忙处理
如果未请求关闭,请执行以下操作:
忙处理=真
对于范围(10)内的i:
印刷品((i+1),“共10页”)
睡眠时间(0.2)
如果强制关闭,lbl[“text”]=str(time.time())#将出错。
root.update()#强制重画,因为我们在一行中多次更改标签。
忙处理=假
root.after(500,定期呼叫)
其他:
打印(“在:,time.time()处销毁GUI”)
试试:#“destroy()”可以抛出,所以你应该像这样包装它。
root.destroy()
除:
#注意:在大多数代码中,您都希望通过
#如果窗口未能销毁,则“退出”。只要确保
#在调用`mainloop()`之后没有代码(在
#因为退出调用将导致
#进程立即终止,不再运行
#代码。当然,您永远不应该在
#`mainloop()`无论如何都要调用设计良好的代码。。。
#出口(0)
通过
root.after\u idle(定期调用)
root.mainloop()
import tkinter as tk
win=tk.Tk
def exit():
    break
btn= tk.Button(win, text="press to exit", command=exit)
win.mainloop()
import tkinter as tk
import sys
win=tk.Tk
def exit():
    sys.exit
btn= tk.Button(win, text="press to exit", command=exit)
win.mainloop()
yourwindow.protocol("WM_DELETE_WINDOW", whatever)
def whatever():
    #Replace this with what you want python to do when the user hits the x button
yourwindow.withdraw() 
yourwindow.deiconify()
   from Tkinter import *
   root = Tk()
   Button(root, text="Quit", command=root.destroy).pack()
   root.mainloop()
from Tkinter import *
def quit():
    global root
    root.quit()

root = Tk()
while True:
    Button(root, text="Quit", command=quit).pack()
    root.mainloop()
    #do something