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

Qt5.12中Python线程更新QLabel为何一成功一崩溃?

问题:Python原生线程更新Qt GUI组件导致崩溃(Nuke集成PySide2环境)

环境信息

  • 框架:PySide2(Qt 5.12)
  • Python版本:3.7(受Nuke软件限制无法升级)
  • 应用场景:与The Foundry Nuke集成的视觉特效合成GUI工具

问题详情

使用Python原生threading模块执行后台任务(包含数据IO和API请求)时,出现以下异常:

  • 一个线程调用updateStatus函数更新connectionLabel组件,可正常运行;
  • 另一个线程调用同一updateStatus函数更新submitLabel组件,会直接导致程序崩溃,退出码为-1073741819 (0xC0000005)。

已知Qt官方规则:非主线程不允许执行GUI操作(如QLabel.setText()),也了解QThread更适配Qt场景,但因切换至QThread需要创建Worker类并处理大量数据传递,希望尽量保留原生threading模块的实现方式。

尝试互换两个线程的目标函数,崩溃问题依然存在,且执行结果混乱。

复现代码

# PySide2 / QT 5.12
# Python 3.7

import PySide2.QtCore as QtCore
import PySide2.QtGui as QtGui
import PySide2.QtWidgets as QtWidgets

import time
import sys
import threading

class MyMainWindow(QtWidgets.QWidget):

    def __init__(self, pathToFile):
        super(MyMainWindow, self).__init__()
        self.resize(250, 200)
        self.connectionEstablished = False
        self.inputFile = pathToFile
        self.createWidgets()
        self.layoutWidgets()

    def startConnectionThread(self):
        self.connectionValid = False
        # 该状态不会在UI中显示,但updateStatus会打印,推测被connectAPI内的首次updateStatus立即覆盖
        self.updateStatus(self.connectionLabel, 'inprogress', '尝试连接')
        connectionThread = threading.Thread(target=self.connectAPI)
        connectionThread.start()

    def connectAPI(self):
        print("connectAPI函数")
        # 此处更新QLabel可正常运行,尽管按规则非主线程不应操作GUI
        self.updateStatus(self.connectionLabel, 'inprogress', "搜索中...")
        # 模拟外部API连接与处理
        self.connectionObject = True
        for x in range(0,11):
            print(x)
            time.sleep(0.2)

        if self.connectionObject == False:
            self.updateStatus(self.connectionLabel, 'failure', "未找到对象!")
            return False
        else:
            self.objectFound = True
        # 此处更新QLabel可正常运行,尽管按规则非主线程不应操作GUI
        self.updateStatus(self.connectionLabel, 'success', "搜索完成")

    def updateStatus(self, label, color, text):
        print(f"更新状态: {text}")
        if color == 'success':
            color = 'ForestGreen'
        if color == 'failure':
            color = 'OrangeRed'
        elif color == 'inprogress':
            color = 'Tan'
        label.setText('<FONT COLOR="{color}"><b>{text}<b></FONT>'.format(color=color, text=text))

    def submitButtonThread(self):
        print("启动提交线程")
        submit_thread = threading.Thread(target=self.testFunction)
        submit_thread.start()

    def testFunction(self):
        print("测试函数")
        for x in range(0, 11):
            print(x)
            time.sleep(0.2)

        # 取消注释以下行会导致GUI崩溃,且仅在此函数中出现
        self.updateStatus(self.submitLabel, 'inprogress', '测试函数结束...')


    def createWidgets(self):
        # 组件 - 验证连接按钮
        self.connectionGet = QtWidgets.QPushButton('验证名称')
        self.connectionGet.clicked.connect(self.startConnectionThread)

        # 组件 - 连接状态标签
        self.connectionLabel = QtWidgets.QLabel('')
        self.connectionLabel.sizeHint()
        self.connectionLabel.setAlignment(QtCore.Qt.AlignCenter)

        # 组件 - 提交按钮
        self.createSubmitButton = QtWidgets.QPushButton('创建提交')
        self.createSubmitButton.clicked.connect(self.submitButtonThread)

        # 组件 - 提交状态标签
        self.submitLabel = QtWidgets.QLabel('')
        self.submitLabel.sizeHint()
        self.submitLabel.setAlignment(QtCore.Qt.AlignCenter)
        self.submitLabel.setMaximumHeight(30)

    def layoutWidgets(self):
        self.mainLayout = QtWidgets.QVBoxLayout(self)

        self.connectionGroup = QtWidgets.QGroupBox('API连接')
        connectionLayout = QtWidgets.QGridLayout()
        connectionLayout.addWidget(self.connectionGet, 0, 2, 1, 2)
        connectionLayout.addWidget(self.connectionLabel, 1, 0, 1, 4)
        self.connectionGroup.setLayout(connectionLayout)

        self.creationSection = QtWidgets.QGroupBox('提交区域')
        creationLayout = QtWidgets.QGridLayout()
        creationLayout.addWidget(self.createSubmitButton, 0, 2, 1, 2)
        creationLayout.addWidget(self.submitLabel, 1, 0, 1, 4)
        self.creationSection.setLayout(creationLayout)


        # 添加至主布局
        self.mainLayout.addWidget(self.connectionGroup)
        self.mainLayout.addSpacing(10)
        self.mainLayout.addWidget(self.creationSection)
        self.setLayout(self.mainLayout)


# 此函数为在Nuke内启动GUI的方式,仅作完整性展示
def launchGUI(pathToFile):
    global window
    window = MyMainWindow(pathToFile)
    window.show()


# 用于IDE内测试
if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    global window
    window = MyMainWindow("//Server/path/to/file.txt")
    window.show()
    sys.exit(app.exec_())

测试输出

1. 点击connectionGet按钮的输出

更新状态: 尝试连接 
connectAPI函数 
更新状态: 搜索中... 
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
更新状态: 搜索完成

2. 点击createSubmitButton按钮的输出

启动提交线程 
测试函数 
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
更新状态: 测试函数结束...

Process finished with exit code -1073741819 (0xC0000005)

(程序崩溃)

3. 互换线程目标函数后的测试结果

情况1:将连接线程目标改为testFunction

connectionThread = threading.Thread(target=self.testFunction)

输出:

更新状态: 尝试连接 
测试函数 
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
更新状态: 测试函数结束...

Process finished with exit code -1073741819 (0xC0000005)

(程序崩溃)

情况2:将提交线程目标改为connectAPI

submit_thread = threading.Thread(target=self.connectAPI)

输出:

启动提交线程 
connectAPI函数 
更新状态: 搜索中... 
0 
1

Process finished with exit code -1073741819 (0xC0000005)

(程序崩溃)


内容的提问来源于stack exchange,提问作者indoorjetpacks

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 20:15:44