How to create a QQmlComponent from C++ at runtime?

10,855

See Loading QML Objects from C++:

QQuickView view;
view.setSource(QUrl("qrc:/main.qml"));
view.show();
QQuickItem *root = view.rootObject()

QQmlComponent component(view.engine(), QUrl("qrc:/Button.qml"));
QQuickItem *object = qobject_cast<QQuickItem*>(component.create());

Now you created an instance of a custom Button component.

To avoid the Javascript garbage collector to kill it, tell QML that C++ takes care of it:

QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);

You need 2 parents: a visual parent to show the object and a QObject parent, to make sure object is properly deleted when view is deleted.

object->setParentItem(root);
object->setParent(&view);

Feel free to set any property to the object like in QML. To make sure, QML knows about the changes, use the following function:

object->setProperty("color", QVariant(QColor(255, 255, 255)));
object->setProperty("text", QVariant(QString("foo")));

Done.

Alternative QQmlEngine version:

QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QQuickWindow *window = qobject_cast<QQuickWindow*>(engine.rootObjects().at(0));
if (!window) {
    qFatal("Error: Your root item has to be a window.");
    return -1;
}
window->show();
QQuickItem *root = window->contentItem();

QQmlComponent component(&engine, QUrl("qrc:/Button.qml"));
QQuickItem *object = qobject_cast<QQuickItem*>(component.create());

QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);

object->setParentItem(root);
object->setParent(&engine);

object->setProperty("color", QVariant(QColor(255, 255, 255)));
object->setProperty("text", QVariant(QString("foo")));
Share:
10,855
pepe
Author by

pepe

Updated on June 04, 2022

Comments

  • pepe
    pepe about 2 years

    I need to add QML components at runtime from C++ code. I am able to create ApplicationWindow from 'main.qml' file. The window is displayed successfully. The issue is that I am not able to add other QML components to this window. I have button specified in 'button.qml' file. So I tried to create another QQmlComponent and set the ApplicationWindow as parent to the button. The output of obj1->children() shows that the children of type button exists (QQuickItem(0xcc08c0) , Button_QMLTYPE_12(0xa7e6d0) ). But the button is not displayed. When I try to add Button staticaly into 'main.qml' everything works well. I am missing something in creation of QQmlComponent at runtime.

    QQmlEngine engine;
    
    QQmlComponent component1(&engine, QUrl("qrc:/main.qml"));
    QQmlComponent component2(&engine, QUrl("qrc:/button.qml"));
    
    QObject* obj1 = component1.create();
    QObject* obj2 = component2.create();
    
    obj2->setParent(obj1);
    
  • pepe
    pepe over 9 years
    The Alternative QQmlEngine version works well. The QQuickView will work in older QtQuick versions. I use QtQuick 2.3.