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?
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)
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).