PyQt5运行线程任务时窗口黑屏 原生线程与QThread均无法解决
问题根因
- 线程目标函数传参错误:你创建线程给
target传参、给started信号绑定时,都在函数名后加了括号,相当于直接在主线程同步执行目标函数,完全阻塞了PyQt的UI渲染事件循环,这是窗口黑屏的核心原因。 - 基础依赖缺失:
sender方法调用了time.sleep但未导入time模块,运行会直接抛出异常。 - 消费线程逻辑缺陷:
get_data方法检测到队列为空就直接终止,程序启动初期队列无数据,消费线程会直接退出,无法接收后续生成的内容。 - QThread使用顺序错误:
moveToThread操作需要在绑定信号之前执行,你原来的顺序会导致槽函数还是在主线程运行。
修复后的完整代码
import queue import sys import threading import time from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import * class Test_generator: def __init__(self, queue_obj): super().__init__() self.queue_obj = queue_obj self.running = True # 增加运行标记,方便线程退出 def sender(self): for _ in range(100): if not self.running: break string ="test" self.queue_obj.put(string) time.sleep(1) class Test_collectioner: def __init__(self,queue_obj): self.queue_obj = queue_obj self.running = True def get_data(self): while self.running: if not self.queue_obj.empty(): print("xd") print(self.queue_obj.get(), "xd") else: time.sleep(0.1) # 空队列时短暂休眠,避免占用过多CPU # 规范QThread实现方案 class WorkerThread(QThread): data_ready = pyqtSignal(str) # 用信号传递数据,无需额外队列也可实现通信 def run(self): for _ in range(100): self.data_ready.emit("test") self.msleep(1000) # QThread内置毫秒休眠,无需调用time.sleep class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.GUI() self.setWindowTitle("PyQt5 app") # 方案1:原生线程+队列修复版 self.q = queue.Queue() # 避免用全局变量,改用实例属性 self.test_generator_obj = Test_generator(self.q) self.test_collectioner_obj = Test_collectioner(self.q) # 只传函数名,不加括号 self.t1 = threading.Thread(target=self.test_generator_obj.sender) self.t2 = threading.Thread(target=self.test_collectioner_obj.get_data) self.t1.start() self.t2.start() # 方案2:QThread信号槽版,取消注释即可使用,比队列更简洁 # self.worker = WorkerThread() # self.worker.data_ready.connect(self.handle_new_data) # self.worker.start() # # 程序退出时终止线程 # qApp.aboutToQuit.connect(self.worker.quit) def handle_new_data(self, data): # 主线程处理子线程传过来的数据 print(f"收到数据:{data}") def GUI(self): self.showMaximized() # 窗口关闭时终止线程,避免后台残留 def closeEvent(self, event): if hasattr(self, 'test_generator_obj'): self.test_generator_obj.running = False self.t1.join() if hasattr(self, 'test_collectioner_obj'): self.test_collectioner_obj.running = False self.t2.join() event.accept() if __name__ == '__main__': app = QApplication(sys.argv) window = MainWindow() sys.exit(app.exec_())
关键修改说明
- 线程传参时去掉了函数后的括号,确保目标函数在子线程中运行,不会阻塞主线程UI渲染
- 新增线程运行标记和窗口关闭事件的线程回收逻辑,避免程序退出后后台线程残留
- 调整消费线程逻辑,空队列时短暂休眠降低CPU占用,不会直接退出
- 提供了原生线程+队列和QThread信号槽两种实现方案,你可以根据需求选择
内容的提问来源于stack exchange,提问作者b-garbacz
相关产品推荐
相关产品推荐

