I'm using PyQt5. During MainWindow.__init__ in the code below, I want to initialize some large data (see MainWindow.initData) that takes a long time (20 seconds for example). During that time, I would like to display a progress bar. The progress bar cannot be displayed until after app.exec_() starts executing, thus I cannot call initData from within MainWindow.__init__. So I'm trying to execute initData by posting an event (postEvent) that will cause initData to execute while app.exec_ is executing. I looked at some examples in stackoverflow and arrived at the following code. The event does get posted and initData is called, but the progress bar is not displayed until after initData is completed.
Please advise on how to revise the code so that the progress bar will be displayed while initData is executing. Thanks.
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import QEvent
class MyEvent(QEvent):
idType = QEvent.registerEventType()
def __init__(self, data):
QEvent.__init__(self, MyEvent.idType)
self.data = data
print("MyEvent.idType ", MyEvent.idType)
def get_data(self):
return self.data
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("My MainWindow")
self.qProgressBar = QtWidgets.QProgressBar(self)
self.qProgressBar.setGeometry(100, 100, 200, 30)
self.label = QtWidgets.QLabel("Hello", self)
self.label.setGeometry(50, 50, 200, 20)
tempEvent = MyEvent("12345")
QtWidgets.QApplication.postEvent(self, tempEvent)
def initData(self):
# To demonstrate, do something that takes a long time (for example
# 20 seconds) and update progress bar.
print("begin initData")
loop = 10000
for i in range(loop):
self.qProgressBar.setValue(int((i+1)/loop*100))
for j in range(loop):
temp = i + j
def customEvent(self, event):
print("customEvent:", event.type())
if (event.type() == MyEvent.idType):
self.label.setText("Received : {0}".format(event.get_data()))
self.initData()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
screen = QtWidgets.QDesktopWidget().screenGeometry()
w.setGeometry(screen.width()//2-200, screen.height()//2-200, 400, 400) # x, y, Width, Height
w.show()
sys.exit(app.exec_())
Thanks musicamante. Here is the final result that works!
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import QObject, QThread, pyqtSignal
from time import sleep
class Worker_InitData(QObject):
finished = pyqtSignal()
progress = pyqtSignal(int)
def run(self):
"""Long-running task."""
for i in range(10):
sleep(1)
self.progress.emit(i)
self.finished.emit()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("My MainWindow")
self.qProgressBar = QtWidgets.QProgressBar(self)
self.qProgressBar.setGeometry(100, 100, 200, 30)
self.label = QtWidgets.QLabel("Hello", self)
self.label.setGeometry(50, 50, 200, 20)
self.initData()
def reportProgress(self, i):
self.qProgressBar.setValue(int((i+1)/10*100))
def initData(self):
# Step 2: Create a QThread object
self.thread = QThread()
# Step 3: Create a worker object
self.worker = Worker_InitData()
# Step 4: Move worker to the thread
self.worker.moveToThread(self.thread)
# Step 5: Connect signals and slots
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.progress.connect(self.reportProgress)
# Step 6: Start the thread
self.thread.start()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
screen = QtWidgets.QDesktopWidget().screenGeometry()
w.setGeometry(screen.width()//2-200, screen.height()//2-200, 400, 400) # x, y, Width, Height
w.show()
sys.exit(app.exec_())