从Qt Quick WorkerScript调用Python方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从Qt Quick WorkerScript调用Python方法相关的知识,希望对你有一定的参考价值。

如何从Qt Quick WorkerScript调用Python方法?

Preamble:

我已经设法通过注册QObject的子类从我的QML应用程序访问我的Python方法:

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

所以从我的QML应用程序中,我可以成功调用Foo.bar()

根据我的理解,我应该从WorkerScript调用任何长期运行的函数。

Problem:

如何使用Foo.bar()在后台线程中运行WorkerThread

Per the docsWorkerScripts不能使用import语法,所以我不确定如何在没有导入的情况下访问Foo

Update:

我需要UI能够显示来自Foo.bar()的进度,因为该功能需要一些时间并做几件事。

答案

WorkerScript发送信息的唯一方法是通过sendMessage()

sendMessage(jsobject消息)

将给定消息发送到另一个线程中的工作者脚本处理程序。另一个worker脚本处理程序可以通过onMessage()处理程序接收此消息。

消息对象可能只包含以下类型的值:

  • 布尔值,数字,字符串
  • JavaScript对象和数组
  • ListModel对象(不允许任何其他类型的QObject *)

所有对象和数组都将复制到消息中。除ListModel对象外,其他线程对传入消息的对象的任何修改都不会反映在原始对象中。

但由于它读取了所有复制的元素(ListModel类型除外),因此不可能使用任何继承自QObject类或其方法的对象。


您可以将进度设为pyqtProperty,以便将其暴露给QML,并使用插槽通过QRunnable通过QThreadPool从另一个线程更新其值,更新通过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)

然后你可以通过run_bar()启动它,并通过progress属性显示它:

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
            }
        }
    }
}

完整的示例可以在以下link中找到

以上是关于从Qt Quick WorkerScript调用Python方法的主要内容,如果未能解决你的问题,请参考以下文章

通过消息信号从 QML WorkerScript.sendMessage 调用传递数据

Qt quick 2 绘制方法没有被调用

Qt Quick 从角色返回对象

Qt Quick:如何从ComboBox获取当前文本

Qt Quick:如何从 ComboBox 获取当前文本

QT5.3.1 Quick 开发 --- 项目类型的选择(转)