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

Python中QProgressBar结合QThread无法正常工作的原因咨询

QThread结合QProgressBar的UI阻塞问题解析

尝试用QThread实现QProgressBar的动态更新功能,但代码运行后所有操作都在主线程执行,UI完全阻塞。以下是问题代码:

import sys
from PySide6.QtWidgets import QApplication, QProgressBar, QWidget, QPushButton, QVBoxLayout
from PySide6.QtCore import QThread, Signal
import time


class Thread(QThread):
    change_value = Signal()

    def run(self):
        self.change_value.emit()
            
class Form(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.pgsb = QProgressBar()
        self.pb = QPushButton("Pause")
        self.th = Thread()
        self.init_widget()
        self.th.change_value.connect(self.update_progressbar)
        self.th.start()

    def init_widget(self):
        layout = QVBoxLayout()
        self.setLayout(layout)
        layout.addWidget(self.pgsb)
        layout.addWidget(self.pb)

    def update_progressbar(self):
        cnt = 0
        while True:
            if cnt == 100:
                cnt = 0
            cnt += 1
            self.pgsb.setValue(cnt)
            time.sleep(0.5)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = Form()
    form.show()
    sys.exit(app.exec())

这段代码无法正常工作,但下方代码却能正常运行:

import sys
from PySide6.QtWidgets import QApplication, QProgressBar, QWidget, QPushButton, QVBoxLayout
from PySide6.QtCore import QThread, Signal
import time


class Thread(QThread):
    change_value = Signal(int)

    def run(self):
        cnt = 0
        while True:
            if cnt == 100:
                cnt = 0
            cnt += 1
            self.change_value.emit(cnt)
            time.sleep(0.5)


class Form(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.pgsb = QProgressBar()
        self.th = Thread()
        self.init_widget()
        self.th.change_value.connect(self.update_progressbar)
        self.th.start()

    def init_widget(self):
        layout = QVBoxLayout()
        self.setLayout(layout)
        layout.addWidget(self.pgsb)

    def update_progressbar(self, value):
        self.pgsb.setValue(value)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = Form()
    form.show()
    sys.exit(app.exec())

两段代码的核心差异解析

  1. 线程的作用范围不同

    • 第一段代码中,子线程Thread的run方法只发射一次信号就结束了,耗时的死循环和time.sleep(0.5)都放在了主线程的槽函数update_progressbar里。Qt的信号槽默认会把跨线程的槽函数调度到主线程执行,等于所有耗时操作都卡死了主线程,UI自然无法响应。
    • 第二段代码中,子线程Thread自己承担了耗时的循环和休眠操作,这部分逻辑完全在子线程中运行,不会影响主线程的UI渲染。
  2. 信号的职责不同

    • 第一段的信号只是触发了主线程的耗时任务,完全没发挥子线程的作用。
    • 第二段的信号只负责传递计算好的进度值,主线程的槽函数只做轻量的UI更新操作,符合Qt"子线程处理耗时任务,主线程处理UI"的设计原则。
  3. UI操作的线程规则
    Qt规定所有UI控件的操作必须在主线程执行,第二段代码中更新进度条的操作放在主线程槽函数是正确的;而第一段代码错误地把耗时逻辑放在了主线程,既违反了线程使用规范,又导致UI阻塞。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 18:43:29