如何用停止按钮终止另一个文件中的Tkinter循环?
问题:点击Stop按钮无法终止子线程中的循环
问题根源
- 线程创建错误:创建线程时直接调用了
subroutine.routine(pressed),导致主线程在启动新线程前就执行该函数,死循环会直接卡住主线程,根本无法启动子线程。正确做法是将函数对象传给target,通过args传递参数。 - 值传递的局限性:
pressed是整数(不可变类型),传递给子函数的是值的副本。主线程修改pressed的值后,子函数里的副本不会同步更新,因此永远触发不了break。
解决方案
方案1:用可变对象传递状态
利用Python可变对象(如列表)的引用特性,让子线程能读取到最新状态。
修改subroutine.py:
def routine(pressed_flag): while True: print("hello") if pressed_flag[0] == 1: break
修改主文件:
import tkinter as tk import threading import subroutine # 用列表作为可变容器,存储状态 pressed = [0] def Start_Scan(): global pressed pressed[0] = 0 # 正确传递函数对象和参数,args为元组格式 t = threading.Thread(target=subroutine.routine, args=(pressed,)) t.start() def Stop(): global pressed pressed[0] = 1 # 主窗口逻辑 master = tk.Tk() app = tk.Frame(master) app.grid() start = tk.Button(app, text="Start Scan", command=Start_Scan) stop = tk.Button(app, text="Stop", command=Stop) start.grid() stop.grid() app.mainloop()
方案2:使用threading.Event(推荐)
threading.Event是Python专门用于线程通信的同步原语,比全局变量更安全可靠。
修改subroutine.py:
def routine(stop_event): while not stop_event.is_set(): print("hello")
修改主文件:
import tkinter as tk import threading import subroutine def Start_Scan(): global stop_event # 每次启动扫描时创建新的Event对象 stop_event = threading.Event() t = threading.Thread(target=subroutine.routine, args=(stop_event,)) t.start() def Stop(): global stop_event # 设置事件,触发子线程终止循环 stop_event.set() # 主窗口逻辑 master = tk.Tk() app = tk.Frame(master) app.grid() start = tk.Button(app, text="Start Scan", command=Start_Scan) stop = tk.Button(app, text="Stop", command=Stop) start.grid() stop.grid() app.mainloop()
说明
- 方案1通过可变对象实现状态共享,适合简单场景;
- 方案2用专门的线程同步工具,避免了竞态条件,是更专业的线程通信方式。
内容的提问来源于stack exchange,提问作者Juan Ignacio Ochotorena
相关产品推荐
相关产品推荐

