PyQt5中QProgressDialog进度条提前终止问题求助
问题分析与解决方案
问题原因
- QProgressDialog自动关闭特性:QProgressDialog默认
autoClose属性为True,当进度值达到设定的最大值(100)时会自动关闭窗口。你的代码在开始处理最后一个文件时就发送了100%的进度信号,此时文件还在读取、合并,后续还有保存操作,进度条因此提前关闭。 - 进度更新时机错误:进度计算和信号发射放在了处理每个文件之前,导致最后一个文件的处理、保存阶段没有进度反馈,且直接触发进度条的自动关闭逻辑。
修复方案
1. 禁用进度条自动关闭
创建QProgressDialog时,关闭自动关闭和自动重置特性,手动通过mergeFinished信号控制关闭时机:
self.progress = QProgressDialog(self) self.progress.setLabelText("Merging files...") self.progress.setCancelButton(None) self.progress.setRange(0, 100) # 新增以下两行,禁用自动关闭与重置 self.progress.setAutoClose(False) self.progress.setAutoReset(False) self.progress.show()
2. 调整进度更新时机
将进度信号的发射移到每个文件处理完成之后,确保进度值对应实际完成的工作量:
def merge_excel(self, files): wb_combined = Workbook() ws_combined = wb_combined.active total_files = len(files) for index, filename in enumerate(files, 1): wb = load_workbook(filename, read_only=False) ws = wb.active for row in ws.iter_rows(values_only=True): ws_combined.append(row) # 处理完当前文件后再计算并发送进度 progress = int((index / total_files) * 100) self.progressChanged.emit(progress) wb_combined.save("merged_file.xlsx") self.mergeFinished.emit()
3. 优化线程与信号传递
不需要将信号作为参数传递给ExcelMerger,直接使用ExcelMerger自身的progressChanged信号即可,简化MergeThread的实现:
class MergeThread(QThread): def __init__(self, files, excel_merger): super().__init__() self.files = files self.excel_merger = excel_merger def run(self): self.excel_merger.merge_excel(self.files)
启动线程时改为:
self.thread = MergeThread(files, self.excel_merger) self.thread.start()
修改后的完整代码
import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QFileDialog, QProgressDialog, QWidget from PyQt5.QtCore import pyqtSignal, QObject, QThread from openpyxl import load_workbook, Workbook class ExcelMerger(QObject): progressChanged = pyqtSignal(int) mergeFinished = pyqtSignal() def merge_excel(self, files): wb_combined = Workbook() ws_combined = wb_combined.active total_files = len(files) for index, filename in enumerate(files, 1): wb = load_workbook(filename, read_only=False) ws = wb.active for row in ws.iter_rows(values_only=True): ws_combined.append(row) # 处理完文件后更新进度 progress = int((index / total_files) * 100) self.progressChanged.emit(progress) wb_combined.save("merged_file.xlsx") self.mergeFinished.emit() class MergeThread(QThread): def __init__(self, files, excel_merger): super().__init__() self.files = files self.excel_merger = excel_merger def run(self): self.excel_merger.merge_excel(self.files) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.initUI() self.excel_merger = ExcelMerger() self.excel_merger.progressChanged.connect(self.on_progress_changed) self.excel_merger.mergeFinished.connect(self.on_merge_finished) def initUI(self): self.setWindowTitle('Excel Merger') self.setGeometry(100, 100, 300, 200) layout = QVBoxLayout() self.merge_btn = QPushButton('Merge Excel Files', self) self.merge_btn.clicked.connect(self.merge_files) layout.addWidget(self.merge_btn) self.widget = QWidget() self.widget.setLayout(layout) self.setCentralWidget(self.widget) def merge_files(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog files, _ = QFileDialog.getOpenFileNames(self, "Select Excel files to merge", "", "Excel Files (*.xlsx *.xls)", options=options) if files: self.progress = QProgressDialog(self) self.progress.setLabelText("Merging files...") self.progress.setCancelButton(None) self.progress.setRange(0, 100) # 禁用自动关闭和自动重置 self.progress.setAutoClose(False) self.progress.setAutoReset(False) self.progress.show() self.thread = MergeThread(files, self.excel_merger) self.thread.start() def on_progress_changed(self, value): self.progress.setValue(value) def on_merge_finished(self): self.progress.close() print("Files merged successfully.") if __name__ == '__main__': app = QApplication(sys.argv) ex = MainWindow() ex.show() sys.exit(app.exec_())
内容的提问来源于stack exchange,提问作者Gaurav
相关产品推荐
相关产品推荐

