简体   繁体   中英

Call Python method from Qt Quick WorkerScript

How do I call a Python method from a Qt Quick WorkerScript ?

Preamble:

I have managed to access my Python methods from my QML app by registering a subclass of QObject :

class Foo(QtCore.QObject):
    @QtCore.pyqtSlot()
    def bar(self):
        pass # do stuff here

app = QtGui.QGuiApplication([])
QtQml.qmlRegisterType(Foo, 'Foo', 1, 0, 'Foo')
# more boilerplate Qt/Qt Quick

So from within my QML application, I can successfully invoke Foo.bar() .

And from what I understand, I should call any long-running functions from a WorkerScript .

Problem:

How can I run Foo.bar() in a background thread using WorkerThread ?

Per the docs , WorkerScript s can't use the import syntax, so I'm not sure how I can access Foo without the import.

Update:

I need the UI to be able to display progress from Foo.bar() , since the function takes a little while and does several things.

The only method to send information to the WorkerScript is through sendMessage() :

sendMessage(jsobject message)

Sends the given message to a worker script handler in another thread. The other worker script handler can receive this message through the onMessage() handler.

The message object may only contain values of the following types:

  • boolean, number, string
  • JavaScript objects and arrays
  • ListModel objects (any other type of QObject* is not allowed)

All objects and arrays are copied to the message. With the exception of ListModel objects, any modifications by the other thread to an object passed in message will not be reflected in the original object.

But since it reads all the elements are copied (except those of type ListModel), so it is not possible to use any object that inherits from the QObject class or its methods.


You can make the progress a pyqtProperty so you can expose it to QML , and use a slot to update its values from another thread through QRunnable with QThreadPool , the update is done through QMetaObject::invokeMethod()

class Runnable(QRunnable):
    def __init__(self, obj):
        QRunnable.__init__(self)
        # main thread
        self.obj = obj

    def run(self):
        # another thread
        self.obj.bar()


class Foo(QObject):
    def __init__(self, *args, **kwags):
        QObject.__init__(self, *args, **kwags)
        self._progress = 0

    @pyqtSlot()
    def run_bar(self):
        self.runnable = Runnable(self)
        QThreadPool.globalInstance().start(self.runnable)

    progressChanged = pyqtSignal(int)

    @pyqtProperty(int, notify=progressChanged)
    def progress(self):
        return self._progress


    @pyqtSlot(int)
    def updateProgress(self, value):
        if self._progress == value:
            return
        self._progress = value
        self.progressChanged.emit(self._progress)

    def bar(self):
        for i in range(100):
            QMetaObject.invokeMethod(self, "updateProgress",
                                     Qt.QueuedConnection,
                                     Q_ARG(int, i))
            QThread.msleep(1000)

Then you can start it through run_bar (), and show it through the progress property:

import QtQuick.Controls 1.4
import QtQuick.Layouts 1.0
import QtQuick 2.0
import Foo 1.0

ApplicationWindow{
    width: 300
    height: 300
    visible: true

    Text{
        id:txt
        text: "press me to start"
        anchors.fill: parent
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignHCenter
    }

    Foo{
        id: foo
        onProgressChanged: txt.text= progress
    }

    MouseArea {
        anchors.fill: parent
        onClicked: foo.run_bar()
    }

    statusBar: StatusBar {
        RowLayout {
            anchors.fill: parent
            ProgressBar {
                value: foo.progress
                maximumValue: 100
                anchors.fill: parent
            }
        }
    }
}

The complete example can be found in the following link

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM