简体   繁体   English

从具有指定属性的 C++ 创建 QML object

[英]Create QML object from C++ with specified properties

Dynamically instantiating a QML object from C++ is well documented , but what I can't find is how to instantiate it with pre-specified values for it's properties.从 C++ 动态实例化 QML object 有详细记录,但我找不到的是如何使用预先指定的属性值实例化它。

For example, I am creating a slightly modified SplitView from C++ like this:例如,我正在从 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 ) );

The problem I have is that specifying the orientation of the SplitView after it is instantiated causes it's internal layout to break.我遇到的问题是在实例化指定SplitVieworientation会导致其内部布局中断。 So, is there a way of creating the SplitView with the orientation already specified?那么,有没有一种方法可以创建已指定orientationSplitView

Alternatively I can create both a horizontal and vertical version of SplitView in separate files and instantiate the appropriate one at runtime - but this is less elegant.或者,我可以在单独的文件中同时创建水平和垂直版本的SplitView ,并在运行时实例化适当的版本——但这不太优雅。

Update更新

I found QQmlComponent::beginCreate(QQmlContext* publicContext) :我找到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();

But it had no effect surprisingly.但出乎意料的是没有效果。

For anyone still interested in this problem, in Qt 5 (and so Qt 6), you can also use a custom QQmlContext with QQmlContext::setContextProperty() to setup external property ( orientation in your case):对于仍然对此问题感兴趣的任何人,在 Qt 5(以及 Qt 6)中,您还可以使用带有QQmlContext::setContextProperty()的自定义QQmlContext来设置外部属性(在您的情况下为orientation ):

QQmlEngine engine;

QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextProperty("myCustomOrientation", QVariant::fromValue(orientation));

// you can use a 'myCustomOrientation' property inside Sy_splitView.qml, e.g.
// `orientation: myCustomOrientation`
QQmlComponent splitComp(&engine, QUrl("qrc:/qml/Sy_splitView.qml"));
QObject* splitter = splitComp.create(context);

This should allow you to not fiddle with beginCreate and completeCreate .这应该允许您不摆弄beginCreatecompleteCreate

Update:更新:

There is also QQmlComponent::createWithInitialProperties() (from 5.14 onwards) that allows you to create an object and initialize its properties before the creation process finishes.还有QQmlComponent::createWithInitialProperties() (从 5.14 开始)允许您创建一个 object 并在创建过程完成之前初始化其属性。

(And then QQmlApplicationEngine::setInitialProperties() is the application engine's version of the same functionality) (然后QQmlApplicationEngine::setInitialProperties()是具有相同功能的应用程序引擎版本)

I think you should be able to use a custom QQmlIncubator and the QQmlComponent::create(QQmlIncubator & incubator, QQmlContext * context = 0, QQmlContext * forContext = 0) factory method. 我认为你应该可以使用自定义QQmlIncubatorQQmlComponent::create(QQmlIncubator & incubator, QQmlContext * context = 0, QQmlContext * forContext = 0)工厂方法。

In particular, quoting from the QQmlIncubator documentation : 特别是,引用QQmlIncubator文档

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

Called after the object is first created, but before property bindings are evaluated and, if applicable, QQmlParserStatus::componentComplete() is called. 在首次创建对象之后调用,但在评估属性绑定之前调用,如果适用,则调用QQmlParserStatus :: componentComplete()。 This is equivalent to the point between QQmlComponent::beginCreate() and QQmlComponent::endCreate(), and can be used to assign initial values to the object's properties. 这相当于QQmlComponent :: beginCreate()和QQmlComponent :: endCreate()之间的点,可用于为对象的属性分配初始值。

The default implementation does nothing. 默认实现什么都不做。

I have had similar situation for my own QML component. 我对自己的QML组件有类似的情况。 Just wanted to init some props before running some bindings. 只是想在运行一些绑定之前初始化一些道具。 In pure QML I did it that way: 在纯QML中,我这样做:

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

From C++ I tried that way: 从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();

but I had binding errors because modelClass remains null! 但我有绑定错误,因为modelClass仍然为null! After digging for a while I found the cause. 经过一段时间的挖掘后,我找到了原因。 And it looks reasonable for me. 对我来说这看起来很合理。 I've changed my QML class! 我改变了我的QML课程!

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

Properties with initial values right after invoking beginCreate are not visible from C++, until I call completeCreate(). 在调用completeCreate()之后,在调用beginCreate之后,具有初始值的属性在C ++中是不可见的。 But if I remove initial value property becomes visible and I can initialize it in C++ code 但是,如果我删除初始值属性变得可见,我可以在C ++代码中初始化它

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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