python-3.x QProgressDialog停止得早于预期

hrysbysz  于 2023-10-21  发布在  Python
关注(0)|答案(1)|浏览(120)
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, progress_callback):
        wb_combined = Workbook()
        ws_combined = wb_combined.active

        for index, filename in enumerate(files, 1):
            progress = int((index / len(files)) * 100)
            progress_callback.emit(progress)

            wb = load_workbook(filename, read_only=False)
            ws = wb.active
            for row in ws.iter_rows(values_only=True):
                ws_combined.append(row)

        wb_combined.save("merged_file.xlsx")

        self.mergeFinished.emit()

class MergeThread(QThread):
    def __init__(self, files, excel_merger, progress_callback):
        super().__init__()
        self.files = files
        self.excel_merger = excel_merger
        self.progress_callback = progress_callback

    def run(self):
        self.excel_merger.merge_excel(self.files, self.progress_callback)

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.show()

            self.thread = MergeThread(files, self.excel_merger,           self.excel_merger.progressChanged)
            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_())

我尝试分离合并线程并设置主窗口,然后运行应用程序的事件循环。但是在文件合并完全完成之前进度条停止。
在这个PyQt5代码中,我试图合并多个Excel文件。文件正在正确合并,但显示上传文件百分比的进度条在所有文件合并之前关闭。我不明白为什么会这样

7jmck4yq

7jmck4yq1#

为什么进度对话框会提前停止,是因为默认情况下,一旦达到最大值,它会立即自动重置,这也会自动关闭对话框。因此,解决问题的最简单方法是进行以下更改:

self.progress.setAutoReset(False)

但是,您当前的代码也比实际需要的要复杂得多,并且每次开始合并时都不必要地创建一个新对话框和一个新线程。因此,我在下面提供了一个简化版本的例子。希望我所做的改变是不言自明的:

import sys
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QPushButton, QVBoxLayout,
    QFileDialog, QProgressDialog, QWidget, QMessageBox,
    )
from PyQt5.QtCore import pyqtSignal, QObject, QThread
from openpyxl import load_workbook, Workbook

class ExcelMerger(QObject):
    progressChanged = pyqtSignal(int)
    mergeFinished = pyqtSignal()

    def set_files(self, files):
        self.files = files

    def merge_excel(self):
        wb_combined = Workbook()
        ws_combined = wb_combined.active
        for index, filename in enumerate(self.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 / len(self.files)) * 100)
            self.progressChanged.emit(progress)
        QThread.sleep(1)
        wb_combined.save("merged_file.xlsx")
        self.mergeFinished.emit()

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.progress = QProgressDialog(self)
        self.progress.setLabelText("Merging files...")
        self.progress.setCancelButton(None)
        self.progress.setRange(0, 100)
        self.progress.setAutoReset(False)
        self.thread = QThread(self)
        self.excel_merger = ExcelMerger()
        self.excel_merger.moveToThread(self.thread)
        self.thread.started.connect(self.excel_merger.merge_excel)
        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(900, 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):
        if not self.thread.isRunning():
            files = QFileDialog.getOpenFileNames(
                self, "Select Excel files to merge", "",
                "Excel Files (*.* *.xlsx *.xls)",
                options=QFileDialog.DontUseNativeDialog)[0]
            if files:
                self.excel_merger.set_files(files)
                self.progress.show()
                self.progress.activateWindow()
                self.thread.start()

    def on_progress_changed(self, value):
        self.progress.setValue(value)

    def on_merge_finished(self):
        self.thread.quit()
        self.progress.close()
        print("Files merged successfully.")

    def closeEvent(self, event):
        self.thread.quit()
        self.thread.wait()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = MainWindow()
    ex.show()
    sys.exit(app.exec_())

相关问题