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
相关产品推荐
相关产品推荐

