从 Qt Quick WorkerScript 调用 Python 方法
Posted
技术标签:
【中文标题】从 Qt Quick WorkerScript 调用 Python 方法【英文标题】:Call Python method from Qt Quick WorkerScript 【发布时间】:2018-01-01 20:34:01 【问题描述】:如何从 Qt Quick WorkerScript
调用 Python 方法?
序言:
通过注册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
调用任何长时间运行的函数。
问题:
如何使用WorkerThread
在后台线程中运行Foo.bar()
?
Per the docs、WorkerScript
s 不能使用 import
语法,所以我不确定如何在不导入的情况下访问 Foo
。
更新:
我需要 UI 能够显示来自 Foo.bar()
的进度,因为该函数需要一些时间并且会执行几项操作。
【问题讨论】:
【参考方案1】:向WorkerScript
发送信息的唯一方法是通过sendMessage()
:
sendMessage(jsobject 消息)
将给定消息发送到另一个线程中的工作脚本处理程序。 另一个工作脚本处理程序可以通过 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 中从后台线程运行 Javascript,但不能从 Python 或 C++ 运行? 我只是觉得这很令人惊讶;您可以在WorkerThread
中运行后端代码似乎是合乎逻辑的
如果我使用QThread
,我是否能够向 UI 发送信号以更新状态栏? Foo.bar()
需要做几件事,我希望界面显示它在做什么以上是关于从 Qt Quick WorkerScript 调用 Python 方法的主要内容,如果未能解决你的问题,请参考以下文章