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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 15:48:03