首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何处理Tkinter中的窗口关闭事件?

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

Stack Overflow用户
提问于 2008-09-21 14:46:20
回答 8查看 200.2K关注 0票数 163

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

EN

回答 8

Stack Overflow用户

发布于 2008-09-21 14:51:11

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

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

这里有一个具体的例子:

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()
票数 235
EN

Stack Overflow用户

发布于 2018-04-13 01:50:02

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

from Tkinter import *

def close_window():
  global running
  running = False  # turn off while loop
  print( "Window closed")

root = Tk()
root.protocol("WM_DELETE_WINDOW", close_window)
cv = Canvas(root, width=200, height=200)
cv.pack()

running = True;
# This is an endless loop stopped only by setting 'running' to 'False'
while running: 
  for i in range(200): 
    if not running: 
        break
    cv.create_oval(i, i, i+1, i+1)
    root.update() 

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

票数 17
EN

Stack Overflow用户

发布于 2019-10-20 08:10:36

我要感谢Apostolos的回答引起了我的注意。下面是2019年Python 3的一个更详细的示例,具有更清晰的描述和示例代码。

请注意,当用户关闭窗口时,destroy() (或根本没有自定义窗口关闭处理程序)将立即销毁窗口及其所有正在运行的回调。

这可能对你不好,这取决于你当前的Tkinter活动,特别是在使用tkinter.after (定期回调)的时候。您可能正在使用一个回调函数来处理一些数据并将其写入磁盘...在这种情况下,您显然希望在不被突然终止的情况下完成数据写入。

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

(注意:我通常将GUI设计为封装得很好的类和独立的工作线程,而且我绝对不使用"global“(我使用类实例变量),但这是一个简单的简化示例,用于演示Tk如何在用户关闭窗口时突然终止定期回调...)

from tkinter import *
import time

# Try setting this to False and look at the printed numbers (1 to 10)
# during the work-loop, if you close the window while the periodic_call
# worker is busy working (printing). It will abruptly end the numbers,
# and kill the periodic callback! That's why you should design most
# applications with a safe closing callback as described in this demo.
safe_closing = True

# ---------

busy_processing = False
close_requested = False

def close_window():
    global close_requested
    close_requested = True
    print("User requested close at:", time.time(), "Was busy processing:", busy_processing)

root = Tk()
if safe_closing:
    root.protocol("WM_DELETE_WINDOW", close_window)
lbl = Label(root)
lbl.pack()

def periodic_call():
    global busy_processing

    if not close_requested:
        busy_processing = True
        for i in range(10):
            print((i+1), "of 10")
            time.sleep(0.2)
            lbl["text"] = str(time.time()) # Will error if force-closed.
            root.update() # Force redrawing since we change label multiple times in a row.
        busy_processing = False
        root.after(500, periodic_call)
    else:
        print("Destroying GUI at:", time.time())
        try: # "destroy()" can throw, so you should wrap it like this.
            root.destroy()
        except:
            # NOTE: In most code, you'll wanna force a close here via
            # "exit" if the window failed to destroy. Just ensure that
            # you have no code after your `mainloop()` call (at the
            # bottom of this file), since the exit call will cause the
            # process to terminate immediately without running any more
            # code. Of course, you should NEVER have code after your
            # `mainloop()` call in well-designed code anyway...
            # exit(0)
            pass

root.after_idle(periodic_call)
root.mainloop()

这段代码将向您展示,即使我们的自定义periodic_call()正忙于工作/循环,WM_DELETE_WINDOW处理程序也会运行!

我们使用了一些非常夸张的.after()值: 500毫秒。这只是为了让您很容易地看到在定期调用忙或不忙时关闭之间的区别……如果您在号码更新时关闭,您将看到在定期调用“忙于处理: True”时发生了WM_DELETE_WINDOW。如果您在数字暂停时关闭(意味着此时周期性回调没有处理),您会看到关闭发生在它“不忙”的时候。

在实际使用中,您的.after()需要大约30-100毫秒的时间才能有一个响应式的图形用户界面。这只是一个演示,帮助您了解如何保护自己免受Tk默认的“关闭时立即中断所有工作”行为的影响。

总而言之:让WM_DELETE_WINDOW处理程序设置一个标志,然后定期检查该标志,并在窗口安全时(当您的应用程序完成所有工作后)手动.destroy()窗口。

PS:你也可以使用WM_DELETE_WINDOW来询问用户是否真的想关闭窗口;如果他们回答否,你就不需要设置标志。这很简单。您只需在WM_DELETE_WINDOW中显示一个消息框,并根据用户的回答设置标志即可。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/111155

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档