28. Using a QThread subclass
Perhaps the most important thing to remember about QThread is that a QThread object does not represent an operating system thread - it is a thread manager. In practice, this means only the QThread.run() method executes in the new thread. All other QThread methods run in the thread that created the QThread object.
Another point when subclassing QThread is that a QThread subclass does not start its event loop unless you explicitly call QThread.exec() in your QThread.run() implementation.
28.1 A Minimal Example
There are two ways to use QThread to run a background task:
- Create a worker object and move it to a background thread using
QObject.moveToThread(). - Create a
QThreadsubclass and override itsrun()method.
The examples from the previous chapter used QObject.moveToThread(). Now let’s examine a minimal QThread subclass.
![]() |
You need to provide a working multithreading application by subclassing |
- Create a
QThreadsubclass (namedWorkerThreadin the example) and override itsrun()method. Add custom signals to the subclass and emit them fromrun()to communicate with the main thread.
In your main window class, create a
WorkerThreadinstance.Connect the
WorkerThreadsignals to main window slots. Also connectWorkerThread.finished()toWorkerThread.deleteLater()for clean thread exit.Create slots in the main window to handle
WorkerThreadsignals. Here, we set aQLabels text to “Hello, World” onWorkerThread.result_ready().Start the worker thread.
When creating a plain QThread object (as in moveToThread() examples) the sequence is:
- Call
QThread.start()from the main thread. - The background
QThreademitsstarted(). QThread.start()invokesQThread.run().QThread.run()callsQThread.exec().QThread.exec()enters the thread-local event loop, waiting forQThread.exit()orQThread.quit().- Call
QThread.exit()orQThread.quit()to stop. - The event loop stops, emitting
QThread.finished() QObjectswithQObject.deleteLater()are deleted.
(Remember that in moveToThread() examples, we connected QThread.started() to a worker slot for immediate execution; and worker finished() to QThread.quit() for thread completion.)
When subclassing QThread, no local event loop unless QThread.exec() is called in run(). Without it, classes that need an event loop (e.g., QTimer, QTcpSocket, QProcess) won’t work. However, the thread object will still be able to emit signals.
In this example, Window.start_work_in_a_thread() runs in the main thread (QThread.loopLevel() = 1, event loop active). WorkerThread.__init__() also runs in the main thread, while only WorkerThread.run() executes in the worker thread (QThread.loopLevel() = 0, no event loop).
28.2 Walking the Filesystem
![]() |
Now let’s walk the filesystem using a |
- Create a
QThreadsubclass namedWorkerThreadand overriderun(). Inrun(), print the current thread object name to confirm execution in the worker thread, then useos.walk()for recursive traversal. Emitprogress()with each object’s name as the argument.
On start button click, create a
WorkerThreadobject and set its name to “Worker thread”.Connect signals to slots:
WorkerThread.progress()toWindow.on_progress()for label updates;WorkerThread.finished()toWorkerThread.deleteLater()for cleanup.Handle signals. On
progress()update the label; On cancel request interruption withQThread.requestInterruption()and wait for finish.Start the worker thread on each start button click.
Override Qwidget.closeEvent() to ensure thread deletion on window close. Note that we didn’t need to call QThread.quit() but only QThread.wait() since no event loop runs.
