Implementing QProgressBar against a class

2020-05-06 14:24发布

问题:

My PyQt program has 2 widgets (selecting files etc) and then a Main Window which displays the results of the parsed files.

The program works great for small sample files, but when trying to parse larger files it will hang (display "Not Responding") and then show the results after about 30 seconds or so.

I would like to implement a QDialog before the Main Window opens. The QDialog will have a progress bar to let the user know when the Main Window will open.

This progress bar needs to be set to the length of time before the Main Window pops up.

What is the best way to implement this? I have seen some examples, but the progress bar is just set to a standardised time, not when the processing(parsing) is complete.

I currently have the following code which opens the Main Window.

def openWidgetMain(self):
        self.WidgetMain = WidgetMain()
        self.WidgetMain.show()
        self.close()

All the processing for this window is done when it opens. So how do I connect the QProgressBar?

回答1:

First, best way to implement this, Your must estimate your load progress file. Next, implement it with QtCore.QThread to create background process. Last, put your call back progress into your QtGui.QMainWindow.

Little example;

import sys
import time
from PyQt4 import QtGui
from PyQt4 import QtCore

class QCustomThread (QtCore.QThread):
    startLoad    = QtCore.pyqtSignal(int)
    progressLoad = QtCore.pyqtSignal(int)
    statusLoad   = QtCore.pyqtSignal(bool)

    def __init__ (self, parentQWidget = None):
        super(QCustomThread, self).__init__(parentQWidget)
        self.wasCanceled = False

    def run (self):
        # Simulate data load estimation
        numberOfprogress = 100
        self.startLoad.emit(numberOfprogress)
        for progress in range(numberOfprogress + 1):
            # Delay
            time.sleep(0.1)
            if not self.wasCanceled:
                self.progressLoad.emit(progress)
            else:
                break
        self.statusLoad.emit(True if progress == numberOfprogress else False)
        self.exit(0)

    def cancel (self):
        self.wasCanceled = True

class QCustomMainWindow (QtGui.QMainWindow):
    def __init__ (self):
        super(QCustomMainWindow, self).__init__()
        # Create action with QPushButton
        self.startQPushButton = QtGui.QPushButton('START')
        self.startQPushButton.released.connect(self.startWork)
        self.setCentralWidget(self.startQPushButton)
        # Create QProgressDialog
        self.loadingQProgressDialog = QtGui.QProgressDialog(self)
        self.loadingQProgressDialog.setLabelText('Loading')
        self.loadingQProgressDialog.setCancelButtonText('Cancel')
        self.loadingQProgressDialog.setWindowModality(QtCore.Qt.WindowModal)

    def startWork (self):
        myQCustomThread = QCustomThread(self)
        def startLoadCallBack (numberOfprogress):
            self.loadingQProgressDialog.setMinimum(0)
            self.loadingQProgressDialog.setMaximum(numberOfprogress)
            self.loadingQProgressDialog.show()
        def progressLoadCallBack (progress):
            self.loadingQProgressDialog.setValue(progress)
        def statusLoadCallBack (flag):
            print 'SUCCESSFUL' if flag else 'FAILED'
        myQCustomThread.startLoad.connect(startLoadCallBack)
        myQCustomThread.progressLoad.connect(progressLoadCallBack)
        myQCustomThread.statusLoad.connect(statusLoadCallBack)
        self.loadingQProgressDialog.canceled.connect(myQCustomThread.cancel)
        myQCustomThread.start()

myQApplication = QtGui.QApplication(sys.argv)
myQCustomMainWindow = QCustomMainWindow()
myQCustomMainWindow.show()
sys.exit(myQApplication.exec_())

More infomation of QtCore.QThread (Recommend read to understand behavior)



回答2:

Put your long lasting process in some kind of thread. Read this: http://qt-project.org/doc/qt-5/threads-technologies.html Emit a signal from that thread to update your progress bar. This way your application will not hang and the user sees the progress.

However it is up to your loading routine to decide which percentage to show in the progress bar. If you can't calculate an exact percentage try some kind of estimation (e.g. based on the size of the file vs. processed amount of the file).