[英]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.我遇到的问题是在实例化后指定
SplitView
的orientation
会导致其内部布局中断。 So, is there a way of creating the SplitView
with the orientation
already specified?那么,有没有一种方法可以创建已指定
orientation
的SplitView
?
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
.这应该允许您不摆弄
beginCreate
和completeCreate
。
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. 我认为你应该可以使用自定义
QQmlIncubator
和QQmlComponent::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.