You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现tkinter点击关闭按钮后等待子线程执行完毕再退出程序

问题根因

两种退出方式的逻辑差异是问题的核心原因:

  • 点击自定义Quit按钮:仅修改全局stop标志,主线程仍在运行Tkinter事件循环,子线程执行完当前20秒的selenium任务后,检测到stop=True就会主动退出,流程完全正常。
  • 点击右上角关闭按钮:修改stop标志后立刻调用root.quit()终止主线程,而你创建的子线程设置了daemon=True,守护线程会随着主线程的退出被强制终止,此时子线程还在执行selenium逻辑就被中断,因此出现无响应。

解决方案

要实现关闭窗口时先等待子线程执行完成再退出,按如下规则修改代码即可:

  1. 把子线程实例改为全局变量,方便关闭回调中访问
  2. 调整on_closing逻辑,先等待子线程执行完成,再退出主线程

修改后完整代码

import tkinter as tk
import threading as th

# 全局变量存储子线程实例,初始为None
p1 = None
stop = False
# 此处保留你原有已定义的kansai、lbl对象逻辑

def start():
    global p1
    def script(object):
        global stop
        stop = False
        while not stop:
            lbl['text'] = object.compare()

    p1 = th.Thread(target=script, args=[kansai], daemon=True)
    p1.start()

def stop():
    global stop
    stop = True


def on_closing():
    global stop, p1
    stop = True
    # 判断子线程是否存在且正在运行
    if p1 is not None and p1.is_alive():
        # 等待子线程结束,每次等待0.5秒就刷新一次界面,避免系统判定界面无响应
        while p1.is_alive():
            p1.join(timeout=0.5)
            root.update()
    # 子线程退出后再关闭主窗口
    root.quit()

root = tk.Tk()
# 此处保留你原有lbl组件的定义和布局逻辑

start_btn = tk.Button(root, text='Start', command=start)
start_btn.grid(column=1, row=3)
quit_btn = tk.Button(root, text='Quit', command=stop)
quit_btn.grid(column=3, row=3)

root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()

关键修改说明

  • 新增全局变量p1存储子线程实例,保证on_closing回调中可以访问到运行中的子线程
  • on_closing中调用带超时的join方法等待子线程,每次超时后调用root.update()处理Tkinter事件,避免窗口在20秒等待过程中被系统标记为未响应
  • 确认子线程完全退出后,再执行root.quit()终止主线程,不会强制中断正在运行的selenium逻辑

内容的提问来源于stack exchange,提问作者Leo_Liu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 07:12:00