TKinter程序无响应求助:线程使用后仍异常,含文件占用错误
问题描述
我正在运行一个包含3个测试用例的Tkinter程序,但程序出现无响应状态。尝试用线程解决后情况依旧,还出现错误提示:The process cannot access the file because it is being used by another process.。不确定线程是否会在设定时长后终止,看起来线程并未结束,恳请帮忙检查代码。
用户提供的代码:
import threading from tkinter import * import time import random import os import datetime import Test_cases Tc =Test_cases.Test() class Blocking(): def __init__(self): self.window_main = Tk(className='Naren-App',) self.window_main.geometry("600x300") Label(self.window_main, text="Stability Tool").place(x=460, y=100, anchor="center") # adding a label Frame to the Main window self.Frame_window = LabelFrame(self.window_main, text = 'Test Cases') self.Frame_window.config(width=400, height=800) self.Frame_window.place(x=300, y=200, anchor="center") self.var1 = IntVar() self.Check_Button_1 = Checkbutton(self.Frame_window, text = "Screen_ON_OFF_Test",variable=self.var1).pack() self.var2 = IntVar() self.Check_Button_2 = Checkbutton(self.Frame_window, text = "WWAN_LPM_To_Online",variable=self.var2).pack() self.var3 = IntVar() self.Check_Button_3 = Checkbutton(self.Frame_window, text = "Get_Device_State",variable=self.var3).pack() Label(self.Frame_window, text="Enter Each Test Duration in Sec").pack() self.Duration = IntVar() # to set default value self.TestDuration = Entry(self.Frame_window, textvariable=self.Duration).pack() #submitBtn = Button(self.Frame_window, text="submit", command=lambda:submit(Check_Button_1.get(),Check_Button_2.get(),Check_Button_3.get())) self.submitBtn = Button(self.Frame_window, text="submit", bg='blue',state=NORMAL,command=self.submit) self.submitBtn.pack() #stability self.Frame_window = LabelFrame(self.window_main, text = 'Stability') self.Frame_window.config(width=400, height=800) self.Frame_window.place(x=600, y=200, anchor="center") self.var4 = IntVar() self.Test_Name_Check_button = Checkbutton(self.Frame_window, text = "Test_Name",variable=self.var4).pack() self.var5 = IntVar() self.NumberOf_Iterations_Check_button = Checkbutton(self.Frame_window, text = "NumberOf_Iterations",variable=self.var5).pack() self.var6 = IntVar() self.NumberOf_Hours_Check_button = Checkbutton(self.Frame_window, text = "NumberOf_Hours",variable=self.var6).pack() self.submitBtn2 = Button(self.Frame_window, text="submit", bg='blue', state =DISABLED,command=self.submit) self.submitBtn2.pack() self.window_main.mainloop() def submit(self): print("var1: %d,\n var2: %d,\nvar3: %d,\nDuration: %d" % (self.var1.get(), self.var2.get() , self.var3.get(), self.Duration.get())) TestDuration = int(self.Duration.get()) print("Test Duration2:", TestDuration) Tc.Duration = TestDuration print("Passing Duration:", Tc.Duration) self.submitBtn['bg']='blue' self.submitBtn['state']=DISABLED if self.var1.get() == 1 : print("Starting Screen on off \n") print("Screen On OFF Test Will run For:",TestDuration ,"sec \n") T1=threading.Thread(target=Tc.Screen_ON_OFF()).start() time.sleep(TestDuration+5) #T1.join() if self.var2.get() == 1 : print("Starting LPM to Online \n") print("LPM to Online Test Will run For:",TestDuration ,"sec \n") T2=threading.Thread(target=Tc.LPM_To_Online()).start() time.sleep(TestDuration+5) if self.var3.get() == 1 : print("Getting device state \n") print("Getting device statet Will run For:",TestDuration ,"sec \n") T1=threading.Thread(target=Tc.Get_Device_State()).start() time.sleep(TestDuration+5) return Label(self.window_main, text="Submitted!").pack() def main(): block = Blocking() if __name__ == '__main__': main()
问题分析与修复方案
1. 线程创建错误导致UI阻塞
你创建线程的写法完全错误:threading.Thread(target=Tc.Screen_ON_OFF()).start() 会直接在主线程中执行Tc.Screen_ON_OFF(),而非把它作为目标函数交给子线程执行。这会导致主线程被测试逻辑卡死,Tkinter事件循环无法运行,程序直接无响应。
正确写法是传入函数对象(不要加括号):
T1 = threading.Thread(target=Tc.Screen_ON_OFF) T1.start()
2. time.sleep()阻塞主线程
submit方法中每次启动线程后调用time.sleep(TestDuration+5),会让主线程进入休眠状态,完全阻塞Tkinter的事件循环,这是程序无响应的核心原因。
解决方式:
- 删掉所有
time.sleep()调用 - 让测试线程自身管理运行时长,或用Tkinter的
after()方法定期检查线程状态,而非在主线程中等待
3. 文件占用错误
The process cannot access the file because it is being used by another process 大概率是Test_cases模块中存在以下问题:
- 多个测试用例同时操作同一个文件,且未正确关闭
- 文件操作未加锁,导致线程间资源竞争
修复方式:
- 所有文件操作使用
with语句自动关闭文件:with open("test_log.txt", "a", encoding="utf-8") as f: f.write(f"{datetime.datetime.now()} - 测试日志\n") - 多线程操作同一文件时加锁:
file_lock = threading.Lock() def safe_write_log(content): with file_lock: with open("test_log.txt", "a", encoding="utf-8") as f: f.write(content + "\n")
4. 线程未正确终止
要确保测试线程能在设定时长后自动停止,需在Test_cases的测试方法中加入超时逻辑:
class Test: def __init__(self): self.duration = 0 def Screen_ON_OFF(self): start_time = time.time() while time.time() - start_time < self.duration: # 执行你的测试逻辑 time.sleep(1) # 模拟测试间隔 print("Screen_ON_OFF测试结束")
修复后的完整代码示例
import threading from tkinter import * import time import datetime import Test_cases Tc = Test_cases.Test() file_lock = threading.Lock() # 文件操作锁 class Blocking(): def __init__(self): self.window_main = Tk(className='Naren-App') self.window_main.geometry("900x500") # 调整窗口大小避免控件重叠 Label(self.window_main, text="Stability Tool").place(x=450, y=50, anchor="center") # 测试用例框架 self.test_frame = LabelFrame(self.window_main, text='Test Cases') self.test_frame.config(width=400, height=400) self.test_frame.place(x=200, y=250, anchor="center") self.var1 = IntVar() Checkbutton(self.test_frame, text="Screen_ON_OFF_Test", variable=self.var1).pack(pady=5) self.var2 = IntVar() Checkbutton(self.test_frame, text="WWAN_LPM_To_Online", variable=self.var2).pack(pady=5) self.var3 = IntVar() Checkbutton(self.test_frame, text="Get_Device_State", variable=self.var3).pack(pady=5) Label(self.test_frame, text="Enter Each Test Duration in Sec").pack(pady=10) self.Duration = IntVar(value=60) # 设置默认时长 Entry(self.test_frame, textvariable=self.Duration).pack(pady=5) self.submitBtn = Button(self.test_frame, text="submit", bg='blue', state=NORMAL, command=self.submit) self.submitBtn.pack(pady=20) # 稳定性框架 self.stability_frame = LabelFrame(self.window_main, text='Stability') self.stability_frame.config(width=400, height=400) self.stability_frame.place(x=700, y=250, anchor="center") self.var4 = IntVar() Checkbutton(self.stability_frame, text="Test_Name", variable=self.var4).pack(pady=5) self.var5 = IntVar() Checkbutton(self.stability_frame, text="NumberOf_Iterations", variable=self.var5).pack(pady=5) self.var6 = IntVar() Checkbutton(self.stability_frame, text="NumberOf_Hours", variable=self.var6).pack(pady=5) self.submitBtn2 = Button(self.stability_frame, text="submit", bg='blue', state=DISABLED, command=self.submit) self.submitBtn2.pack(pady=20) # 状态提示标签 self.status_label = Label(self.window_main, text="") self.status_label.place(x=450, y=450, anchor="center") self.window_main.mainloop() def submit(self): var1 = self.var1.get() var2 = self.var2.get() var3 = self.var3.get() TestDuration = int(self.Duration.get()) print(f"var1: {var1},\nvar2: {var2},\nvar3: {var3},\nDuration: {TestDuration}") Tc.Duration = TestDuration print("Passing Duration:", Tc.Duration) self.submitBtn['state'] = DISABLED self.status_label.config(text="测试正在运行...") # 启动选中的测试线程 threads = [] if var1 == 1: print("Starting Screen on off \n") print(f"Screen On OFF Test Will run For: {TestDuration} sec \n") t = threading.Thread(target=Tc.Screen_ON_OFF) threads.append(t) t.start() if var2 == 1: print("Starting LPM to Online \n") print(f"LPM to Online Test Will run For: {TestDuration} sec \n") t = threading.Thread(target=Tc.LPM_To_Online) threads.append(t) t.start() if var3 == 1: print("Getting device state \n") print(f"Getting device state Will run For: {TestDuration} sec \n") t = threading.Thread(target=Tc.Get_Device_State) threads.append(t) t.start() # 定期检查线程是否全部完成 def check_threads(): all_done = all(not t.is_alive() for t in threads) if all_done: self.submitBtn['state'] = NORMAL self.status_label.config(text="测试完成!") else: self.window_main.after(1000, check_threads) self.window_main.after(1000, check_threads) def main(): block = Blocking() if __name__ == '__main__': main()
额外优化说明
- 控件变量赋值:原代码中
self.Check_Button_1 = Checkbutton(...).pack()会让变量等于None(pack()返回值),实际不需要保存按钮对象,直接调用pack()即可 - 窗口布局:调整了窗口大小和控件位置,避免两个
LabelFrame重叠 - 状态反馈:添加了状态标签,让用户直观了解测试运行状态
内容的提问来源于stack exchange,提问作者NBK_Coder
相关产品推荐
相关产品推荐

