【问题标题】:Create QML object from C++ with specified properties从 C++ 创建具有指定属性的 QML 对象
【发布时间】:2013-11-10 14:22:33
【问题描述】:

从 C++ 动态实例化 QML 对象是 well documented,但我找不到如何使用预先指定的属性值来实例化它。

例如,我正在从 C++ 创建一个稍微修改的SplitView,如下所示:

QQmlEngine* engine = QtQml::qmlEngine( this );
QQmlComponent splitComp( engine, QUrl( "qrc:/qml/Sy_splitView.qml" ) );
QObject* splitter = splitComp.create();

splitter->setProperty( "orientation", QVariant::fromValue( orientation ) );

我遇到的问题是,指定SplitVieworientation 实例化后会导致其内部布局中断。那么,有没有办法在已经指定 orientation 的情况下创建 SplitView

或者,我可以在单独的文件中创建SplitView 的水平和垂直版本,并在运行时实例化适当的版本 - 但这不太优雅。

更新

我找到QQmlComponent::beginCreate(QQmlContext* publicContext):

QQmlEngine* engine = QtQml::qmlEngine( this );
QQmlComponent splitComp( engine, QUrl( "qrc:/qml/Sy_splitView.qml" ) );
QObject* splitter = splitComp.beginCreate( engine->contextForObject( this ) );

splitter->setProperty( "orientation", QVariant::fromValue( orientation ) );
splitter->setParent( parent() );
splitter->setProperty( "parent", QVariant::fromValue( parent() ) );
splitComp.completeCreate();

但出乎意料的没有效果。

【问题讨论】:

  • 我敢打赌,问题在于您如何尝试通过 QVariant 分配枚举(枚举在 QML 中有些错误)。我会尝试首先注册一个简单的基于 QObject 的类型和一个自定义枚举,然后检查整个事情是否有效。 [另请注意,您显然尝试设置 parent 两次,但这是次要的]
  • 我对枚举一​​无所知,所以谢谢,我会试试的。而且我没有设置父级两次,我首先设置QObject父级,然后是QML视觉父级(如果我可以通过QML设置QObject父级,我根本不会为此烦恼C++ )。
  • 没错,确实;我相信,您可以将内存所有权(或无论如何调用)设置为 QmlOwnership,而不是设置 QObject 父级(以便 QML 运行时根据需要对新创建的对象进行垃圾收集/引用计数)。顺便说一句,您是否出于内存管理以外的某些原因特别需要设置 QObject 父级?
  • 用于内存管理。每个SplitView 包含两个自定义OSG 视口,每个视口又可以无限分割(如Qt Creator 的文本编辑器窗格),形成一棵树。因此,当我删除特定的拆分器时,它会适当地删除所有子级。我会看看在 QML 方面拥有所有权,它可能会简化事情 - 谢谢!

标签: c++ qt qml qt-quick


【解决方案1】:

我认为您应该能够使用自定义 QQmlIncubatorQQmlComponent::create(QQmlIncubator & incubator, QQmlContext * context = 0, QQmlContext * forContext = 0) 工厂方法。

特别是引用the QQmlIncubator documentation:

void QQmlIncubator::setInitialState(QObject * object) [虚拟保护]

在第一次创建对象之后调用,但在评估属性绑定之前调用,如果适用,调用 QQmlParserStatus::componentComplete()。这相当于 QQmlComponent::beginCreate() 和 QQmlComponent::endCreate() 之间的点,可用于为对象的属性分配初始值。

默认实现什么都不做。

【讨论】:

    【解决方案2】:

    我自己的 QML 组件也遇到过类似的情况。只是想在运行一些绑定之前初始化一些道具。在纯 QML 中,我是这样做的:

    var some = component.createObject(this, {'modelClass': my_model});
    

    在 C++ 中我尝试过这种方式:

    // create ui object
    auto uiObject = qobject_cast<QQuickItem*>(component.beginCreate(ctx));
    // place on ui
    uiObject->setParentItem(cont);
    
    // set model properties
    classInstance->setView(QVariant::fromValue(uiObject));
    classInstance->setPosition(QPointF(x, y));
    
    // set ui object properties
    uiObject->setProperty("modelClass", QVariant::fromValue(classInstance.get()));
    
    // finish
    component.completeCreate();
    

    但我遇到了绑定错误,因为 modelClass 仍然为空!经过一段时间的挖掘,我找到了原因。这对我来说看起来很合理。我改变了我的 QML 课程!

    Item {
        id: root
        // property var modelClass: null
        property var modelClass // just remove : null!
    }
    

    在调用 beginCreate 之后具有初始值的属性在 C++ 中不可见,直到我调用 completeCreate()。但是如果我删除初始值属性变得可见,我可以在 C++ 代码中初始化它

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-12
      • 2021-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多