Use the Same QThread
Object Multiple Times
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# https://doc.qt.io/qt-6/qthread.html
import sys
from PySide6.QtCore import (QObject, QThread,
Slot, Signal, Qt)
from PySide6.QtWidgets import (QApplication,
QPushButton, QLabel, QWidget, QVBoxLayout)
# 1. Create the worker class
class Worker(QObject):
result_ready = Signal(str)
def __init__(self, parent=None):
super().__init__(parent)
@Slot()
def do_work(self, parameter):
print(parameter)
self.result_ready.emit(parameter)
class Controller(QWidget):
operate = Signal(str)
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
button = QPushButton('Start background thread')
button.clicked.connect(self.on_button_clicked)
self.label = QLabel()
self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(button)
layout.addWidget(self.label)
# 2. Create the thread object
self.worker_thread = QThread()
# 3. Create the worker and move it to the thread
self.worker = Worker()
self.worker.moveToThread(self.worker_thread)
# 4. Connect the signals and the slots
self.worker_thread.finished.connect(
self.worker.deleteLater)
self.operate.connect(self.worker.do_work)
self.worker.result_ready.connect(self.handle_results)
# 5. Start the thread
self.worker_thread.start()
# 6. On the button click emit the operate signal
@Slot()
def on_button_clicked(self):
self.operate.emit('Hello World')
@Slot()
def handle_results(self):
self.label.setText('Worker finished')
# 7. Quit the thread when the main window is closed
def closeEvent(self, event):
try:
self.worker_thread.quit()
self.worker_thread.wait()
except Exception as e:
print(e)
event.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = Controller()
main_window.show()
sys.exit(app.exec())
In the first two examples the background/worker thread is created each time we want to execute the long running task but in the example from the QThread
documentation both the thread and the worker objects are created in the main class constructor so let’s try to replicate that:
-
Create the worker class. The method to be executed in the background is called
do_work()
just as in theQThread
documentation. Then, in the main window class -
Create the worker thread,
-
Create the
Worker
object and move it to the the worker thread usingQObject.moveToThread()
, -
Connect the signals with the slots. We want the worker object deleted when the thread finishes so we connect
QThread.finished
withQObject.deleteLater
. We want to send a custom signal (operate
) to the worker object to start the work so we connectController.operate
withWorker.do_work
. Finally, we connectWorker.result_ready
withController.handle_result
so we can handle thedo_work
result in the main class. -
Start the worker thread. The steps 2 through 5 are executed in the
Controller.__init__()
method which means both the thread and the worker objects will exist until the main window is closed or we delete them explicitly. -
On the button click emit the
operate
signal. This executes theWorker.do_work()
method. -
Override
QWidget.closeEvent()
to quit the thread using theQThread.quit()
andQThread.wait()
pair.