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

PyQt5中QProgressDialog二次调用无进度更新问题求助

问题:QProgressDialog第二次点击Start按钮无进度更新

用户编写的PyQt5代码实现QProgressDialog功能,首次点击Start按钮执行create函数时进度对话框运行正常;但对话框结束后再次点击Start按钮,进度条显示为空且无进度更新,将对话框设为局部变量后问题仍未解决。

用户原代码如下:

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
import time


class Worker(QObject):
    signal = pyqtSignal(int)

    def __init__(self):
        super().__init__()
    @pyqtSlot()
    def do_work(self) -> None:
        for value in range(1,101):
            self.signal.emit(value)
            time.sleep(0.01)
        

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.layout = QVBoxLayout()
        self.con = QWidget()
        self.setCentralWidget(self.con)
        self.con.setLayout(self.layout)
        self.btn = QPushButton("Start",self)
        self.layout.addWidget(self.btn)
        self.thread = QThread()
        self.thread.finished.connect(self.thread_finished)
        self.btn.pressed.connect(self.create)


    def create(self):
        self.p = QProgressDialog("Names", "Cancel", 0, 100)
        self.p.setValue(0)
        self.p.setWindowModality(Qt.ApplicationModal)
        self.p.canceled.connect(self.p.deleteLater)
        self.p.show()
        self.worker = Worker()
        self.worker.signal.connect(self.p.setValue)
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.do_work)
        self.thread.start()

        
        
    def thread_finished(self):
        self.thread.deletelater()
        # self.thread = QThread()
        # self.thread.finished.connect(self.thread_finished)



app = QApplication(sys.argv)
window = Window()
window.show()
app.exec_()

问题原因

  • QThread对象只能启动一次,首次调用start()后线程进入Finished状态,无法再次启动。原代码中self.thread是全局初始化的线程,第二次点击时调用start()不会生效。
  • 线程结束后仅调用deleteLater()但未重新创建线程对象,后续任务无有效线程可执行。
  • Worker对象绑定到已结束的线程,无法正常发送信号更新进度对话框。

解决方案

每次点击Start按钮时,重新创建QThread和Worker实例,确保每次任务都使用全新的线程环境;同时正确绑定信号槽,管理线程生命周期:

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
import time


class Worker(QObject):
    signal = pyqtSignal(int)
    finished = pyqtSignal()

    def __init__(self):
        super().__init__()

    @pyqtSlot()
    def do_work(self) -> None:
        for value in range(1, 101):
            self.signal.emit(value)
            time.sleep(0.01)
        self.finished.emit()  # 任务完成后发送结束信号


class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.layout = QVBoxLayout()
        self.con = QWidget()
        self.setCentralWidget(self.con)
        self.con.setLayout(self.layout)
        self.btn = QPushButton("Start", self)
        self.layout.addWidget(self.btn)
        self.btn.pressed.connect(self.create)
        # 不再提前初始化线程,每次点击时创建


    def create(self):
        # 禁用按钮,防止重复点击
        self.btn.setEnabled(False)
        
        # 创建进度对话框
        p = QProgressDialog("Names", "Cancel", 0, 100)
        p.setValue(0)
        p.setWindowModality(Qt.ApplicationModal)
        
        # 创建线程和Worker
        thread = QThread()
        worker = Worker()
        
        # 绑定信号槽
        worker.signal.connect(p.setValue)
        worker.finished.connect(thread.quit)  # 任务完成后终止线程
        worker.finished.connect(p.deleteLater)  # 关闭进度对话框
        worker.finished.connect(worker.deleteLater)  # 销毁Worker
        thread.finished.connect(thread.deleteLater)  # 销毁线程
        thread.finished.connect(lambda: self.btn.setEnabled(True))  # 恢复按钮
        
        p.canceled.connect(thread.quit)  # 取消时终止线程
        p.canceled.connect(p.deleteLater)
        p.canceled.connect(worker.deleteLater)
        
        # 启动线程
        worker.moveToThread(thread)
        thread.started.connect(worker.do_work)
        thread.start()
        
        p.exec_()  # 使用exec_()代替show(),确保对话框模态阻塞直到完成或取消


app = QApplication(sys.argv)
window = Window()
window.show()
app.exec_()

关键修改点

  • 移除全局线程,每次点击Start时新建QThread和Worker,避免复用已结束的线程。
  • 为Worker添加finished信号,用于触发线程退出、对话框关闭和资源清理。
  • 禁用Start按钮防止重复点击,任务完成或取消后恢复按钮状态。
  • 使用p.exec_()代替show(),确保进度对话框的模态行为正确,直到任务完成或被取消。
  • 绑定多个清理信号,确保线程、Worker和对话框在任务结束后被正确销毁,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Alexander Ortiz Cuellar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 07:01:03