如何将 __init__ 参数传递给使用 qmlRegisterType 注册的类?

Posted

技术标签:

【中文标题】如何将 __init__ 参数传递给使用 qmlRegisterType 注册的类?【英文标题】:How to pass __init__ arguments to class registered with qmlRegisterType? 【发布时间】:2019-07-22 20:49:05 【问题描述】:

是否可以使用 qmlRegisterType 函数将初始化参数传递给注册到 QML 的 python 类?如果是这样,当类在 QML 中实例化时它们会被传递吗?

我已经使用 qmlRegisterType 注册了该类,但没有看到将另一个类实例作为对象传递的方法。我确实看到有一种注册扩展对象的方法,但根据文档,这些只能是属性。我想传入另一个实例化类,以便我可以在我注册到 QML 的类中访问它的方法和属性。

如何在 Python 中实例化该类:

from PySide2.QtWidgets import QApplication
from PySide2.QtQml import QQmlApplicationEngine, qmlRegisterType, QQmlComponent
from PySide2.QtCore import QObject
from app import Sites
from models import RoutesConn

def main():
    # create the application instance
    app = QApplication(sys.argv)

    # create a QML engine
    engine = QQmlApplicationEngine()

    # instantiate Sites instance
    sites = Sites()
    # instantiate RoutesConn instance, and pass in sites instance
    routesconn = RoutesConn(sites)
    # this could be provided to qml as an object
    engine.rootContext().setContextProperty('RoutesConn', routesconn)

但是,如果在 qml 中注册为类,则站点实例无法传递。我认为站点类也可以注册到 qml 并在 QML 中实例化时传递给 RoutesConn,但我还没有看到这样做的方法。

在 Python 中将类注册到 QML:

qmlRegisterType(RoutesConn, 'RoutesConn', 1, 0, 'RoutesConn')

QML:

import RoutesConn 1.0

RoutesConn 
    id: rconn

    ....

我希望有一种方法可以在注册到 qml 后的初始化期间将对象传递到类中,但事实并非如此。

【问题讨论】:

提供一个minimal reproducible example,显示 Sites 和 RoutesConn 类 要传递给RoutesConn对象的Sites类的对象在哪里创建? 它是在 main() 中创建的,其中应用程序引擎也被加载。我在我的问题中添加了一些额外的代码作为上下文。 【参考方案1】:

TL; DR; 不,这是不可能的。


QML 期望通过 qmlRegisterType 注册的 QObjects 仅具有接收 QObject 作为父对象的构造函数(qmlRegisterType 不构建对象,仅使其在 QML 中可用):

class Foo(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        # ...

如果你想传递其他对象,你必须通过 Slot 或 Property:

在 Component.Completed 中调用 Slot:
from PySide2 import QtCore, QtGui, QtQml


class Bar(QtCore.QObject):
    def test(self):
        print("test")


class Foo(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.m_bar = None

    @QtCore.Slot(Bar)
    def load_bar(self, bar):
        self.m_bar = bar


    @QtCore.Slot()
    def test_bar(self):
        if self.m_bar is not None:
            self.m_bar.test()


if __name__ == "__main__":
    import os
    import sys

    app = QtGui.QGuiApplication(sys.argv)
    QtQml.qmlRegisterType(Foo, 'TestComponents', 1, 0, 'Foo')
    QtQml.qmlRegisterType(Bar, 'TestComponents', 1, 0, 'Bar')
    engine = QtQml.QQmlApplicationEngine()
    file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "main.qml")
    engine.load(file)
    if not engine.rootObjects():
        sys.exit(-2)
    sys.exit(app.exec_())
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls 2.5

import TestComponents 1.0

ApplicationWindow 
    visible: true
    width: 640
    height: 480
    color: "whitesmoke"
    Foo
        id: foo
        Component.onCompleted: load_bar(bar)
    
    Bar
        id: bar
    
    Button 
        text: "Cancel"
        onClicked: foo.test_bar()
        anchors.centerIn: parent
    

财产
from PySide2 import QtCore, QtGui, QtQml


class Bar(QtCore.QObject):
    def test(self):
        print("test")


class Foo(QtCore.QObject):
    barChanged = QtCore.Signal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.m_bar = None

    def getBar(self):
        return self.m_bar

    def setBar(self, bar):
        if self.m_bar != bar:
            self.m_bar = bar
            self.barChanged.emit()

    bar = QtCore.Property(Bar, fget=getBar, fset=setBar, notify=barChanged)

    @QtCore.Slot()
    def test_bar(self):
        if self.m_bar is not None:
            self.m_bar.test()


if __name__ == "__main__":
    import os
    import sys

    app = QtGui.QGuiApplication(sys.argv)
    QtQml.qmlRegisterType(Foo, "TestComponents", 1, 0, "Foo")
    QtQml.qmlRegisterType(Bar, "TestComponents", 1, 0, "Bar")
    engine = QtQml.QQmlApplicationEngine()
    file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "main.qml")
    engine.load(file)
    if not engine.rootObjects():
        sys.exit(-2)
    sys.exit(app.exec_())
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls 2.5

import TestComponents 1.0

ApplicationWindow 
    visible: true
    width: 640
    height: 480
    color: "whitesmoke"
    Foo
        id: foo
        bar: bar_object 
    
    Bar
        id: bar_object
    
    Button 
        text: "Cancel"
        onClicked: foo.test_bar()
        anchors.centerIn: parent
    

【讨论】:

感谢您的详细解答。看起来只要您将这两个类都添加到 QML,那么您就可以在 QML 中将一个类传递给另一个类。这将同样有效并且有意义,因为这些类是在 QML 中实例化的。

以上是关于如何将 __init__ 参数传递给使用 qmlRegisterType 注册的类?的主要内容,如果未能解决你的问题,请参考以下文章

如何将附加参数传递给自定义 python 排序函数

如何将类方法作为参数传递给该类外部的函数?

如何将参数传递给函数的 __code__?

将自定义表单参数传递给表单集

将参数传递给 decontext 装饰器

如何将参数传递给`_T()`? [复制]