I'm trying to write a QT Gui with Python, using a main window and background threads that do the heavy lifting. The main window should have buttons, that launch one background thread, open a separate window that shows the background threads progress in a progress bar and closes the window when done.
I tried to strip away all unnecessary code to yield the following minimal, self-contained example:
import sys
import time
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5 import QtWidgets, uic
from PyQt5.QtWidgets import QMainWindow, QWidget
from pathlib import Path
BAR_UIC = Path(r'bar.ui')
BUTTON_UIC = Path(r'button.ui')
class AThread(QThread):
increasing = pyqtSignal(int)
done = pyqtSignal()
def run(self):
count = 0
while count < 100:
time.sleep(1)
print("A Increasing")
count += 10
self.increasing.emit(count)
self.done.emit()
class BarWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
uic.loadUi(str(BAR_UIC), self)
def update(self, signal):
self.progressBar.setValue(signal)
class ButtonWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi(str(BUTTON_UIC), self)
self.pushButton.clicked.connect(self.launch_thread)
def launch_thread(self):
barwin = BarWindow()
self.thread = AThread()
self.thread.done.connect(barwin.close)
self.thread.increasing.connect(barwin.update)
barwin.show()
self.thread.start()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = ButtonWindow()
mainWin.show()
app.exec_()
The two uic files that are loaded are a simple QMainWindow with a single pushButton (button.uic
):
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>572</width>
<height>337</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>220</x>
<y>130</y>
<width>104</width>
<height>32</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>572</width>
<height>29</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
and a QWidget with a ProgressBar (bar.ui
):
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QProgressBar" name="progressBar">
<property name="geometry">
<rect>
<x>140</x>
<y>120</y>
<width>118</width>
<height>23</height>
</rect>
</property>
<property name="value">
<number>24</number>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
When I run this application (Win 10, python 3.7.4), the main window shows. When I press the button, the second window (with the progress bar) pops up for a second and goes away immediately, wheras I want it to stay until the thread has finished. The console output, shows the print
output of the thread. My second question is, how this console output is possible, as I thought that the QThread is not running in the main shell?