Progress Bar Does not Render Until Job is Complete

前端 未结 1 1135
囚心锁ツ
囚心锁ツ 2020-12-20 07:49

I am trying to make a progress bar for copying large files. However, currently the Dialog window goes black until the process is finished. I now understand I probably have t

相关标签:
1条回答
  • 2020-12-20 08:09

    Heavy tasks should not run on the main thread, you should use a thread. In this case I have replaced your logic, so there is a class that is in charge of copying the files informing through signs of progress, error, etc. An object of that class will live in another thread notifying the GUI through signals, in this case I will use QProgressDialog to show the progress.

    #!/usr/bin/env python
    import os
    import sys
    import shutil
    import threading
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class MainWindow(QtWidgets.QMainWindow):
        startMoveFilesSignal = QtCore.pyqtSignal(str, str)
    
        def __init__(self):
            super(MainWindow, self).__init__()
            srcdir = "/media/zachlab/Windows/LinuxStorage/old/embryos"
            dstdir = "/media/zachlab/Windows/LinuxStorage/old/out"
            self.le_src = QtWidgets.QLineEdit(srcdir)
            self.le_dst = QtWidgets.QLineEdit(dstdir)
            self.button = QtWidgets.QPushButton("Copy")
            self.button.clicked.connect(self.archiveEntry)
    
            central_widget = QtWidgets.QWidget()
            self.setCentralWidget(central_widget)
            lay = QtWidgets.QFormLayout(central_widget)
            lay.addRow("From: ", self.le_src)
            lay.addRow("To: ", self.le_dst)
            lay.addRow(self.button)
    
            self.progressbar = QtWidgets.QProgressDialog(self)
            self.progressbar.hide()
    
            thread = QtCore.QThread(self)
            thread.start()
            self.helper = MoveFileHelper()
            self.startMoveFilesSignal.connect(self.helper.moveFilesWithProgress)
            self.helper.progressChanged.connect(self.progressbar.setValue)
            self.helper.finished.connect(self.on_finished)
            self.helper.started.connect(self.progressbar.show)
            self.helper.errorOccurred.connect(self.on_errorOcurred)
            self.helper.moveToThread(thread)
    
        @QtCore.pyqtSlot()
        def archiveEntry(self):
            self.startMoveFilesSignal.emit(self.le_src.text(), self.le_dst.text())
            self.progressbar.hide()
    
        @QtCore.pyqtSlot()
        def on_finished(self):
            self.button.setText('Finished')
    
        @QtCore.pyqtSlot(str)
        def on_errorOcurred(self, msg):
            QtWidgets.QMessageBox.critical(self, "Error Ocurred", msg)
    
    class MoveFileHelper(QtCore.QObject):
        progressChanged = QtCore.pyqtSignal(int)
        started = QtCore.pyqtSignal()
        finished = QtCore.pyqtSignal()
        errorOccurred = QtCore.pyqtSignal(str)
    
        def calculateAndUpdate(self, done, total):
            progress = int(round((done / float(total)) * 100))
            self.progressChanged.emit(progress)
    
        @staticmethod
        def countFiles(directory):
            count = 0
            if os.path.isdir(directory):
                for path, dirs, filenames in os.walk(directory):
                    count += len(filenames)
            return count
    
        @staticmethod
        def makedirs(dest):
            if not os.path.exists(dest):
                os.makedirs(dest)
    
        @QtCore.pyqtSlot(str, str)
        def moveFilesWithProgress(self, src, dest):
            numFiles = MoveFileHelper.countFiles(src)
            if os.path.exists(dest):
                self.errorOccurred.emit("Dest exist")
                return 
            if numFiles > 0:
                self.started.emit()
                MoveFileHelper.makedirs(dest)
                numCopied = 0
                for path, dirs, filenames in os.walk(src):
                    for directory in dirs:
                        destDir = path.replace(src, dest)
                        MoveFileHelper.makedirs(os.path.join(destDir, directory))
    
                    for sfile in filenames:
                        srcFile = os.path.join(path, sfile)
                        destFile = os.path.join(path.replace(src, dest), sfile)
                        shutil.copy(srcFile, destFile)
                        numCopied += 1
                        self.calculateAndUpdate(numCopied, numFiles)
                self.finished.emit()
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        ex = MainWindow()
        ex.resize(640, ex.sizeHint().height())
        ex.show()
        sys.exit(app.exec_())
    
    0 讨论(0)
提交回复
热议问题