如何实现tkinter点击关闭按钮后等待子线程执行完毕再退出程序
问题根因
两种退出方式的逻辑差异是问题的核心原因:
- 点击自定义
Quit按钮:仅修改全局stop标志,主线程仍在运行Tkinter事件循环,子线程执行完当前20秒的selenium任务后,检测到stop=True就会主动退出,流程完全正常。 - 点击右上角关闭按钮:修改
stop标志后立刻调用root.quit()终止主线程,而你创建的子线程设置了daemon=True,守护线程会随着主线程的退出被强制终止,此时子线程还在执行selenium逻辑就被中断,因此出现无响应。
解决方案
要实现关闭窗口时先等待子线程执行完成再退出,按如下规则修改代码即可:
- 把子线程实例改为全局变量,方便关闭回调中访问
- 调整
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
相关产品推荐
相关产品推荐

