I have a python-defined worker QObject
that has a slow work()
slot that is called by the QML UI (in my actual UI, the method is called on each item in a FolderListModel
dynamically as the user goes through the list, but for he sample code I'm just calling it on the window's completion as an example).
I'd like to run the slow work
asynchronously to prevent the UI from blocking. I thought to do so by moving the Worker instance on a QThread and calling the slot there, but this is not working, as the UI is still blocked waiting for the result of work()
to come.
This is the code of my attempt so far:
mcve.qml:
import QtQuick 2.13
import QtQuick.Window 2.13
Window {
id: window
visible: true
width: 800
height: 600
title: qsTr("Main Window")
Component.onCompleted: console.log(worker.work("I'm done!")) // not the actual usage, see note in the question
}
mcve.py:
import sys
from PySide2.QtWidgets import QApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtCore import QUrl, QThread, QObject, Slot
from time import sleep
class Worker(QObject):
def __init__(self, parent=None):
super().__init__(parent)
@Slot(str, result=str)
def work(self, path):
sleep(5) # do something lengthy
return path
if __name__ == '__main__':
app = QApplication(sys.argv)
engine = QQmlApplicationEngine()
workerThread = QThread()
worker = Worker()
worker.moveToThread(workerThread)
engine.rootContext().setContextProperty("worker", worker)
engine.load(QUrl.fromLocalFile('mcve.qml'))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
How do I invoke work()
asynchronously so that only when it's done its effects are applied? And, as a bonus, what am I doing/understanding wrong in the use of QThreads?