Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Creating and changing qml objects from c++



  • Hi,
    I create a component in c++ and use it as a sourceComponent for a Loader in QML, but - though setProperty returns true - I can't see the properties set by c++.

    The loader approach here is kind of a necessity, because in the end, the object to be created will be a complex, nested structure of qml files (I want to display math formulas). Most of these qml elements have loaders themselves (again: later to be set by c++), here I use the simplest qml (like an end branch of the nested structure).

    I try it this way (shortened code):

    main.cpp:

    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
        QQmlApplicationEngine engine;
    
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;
    
        QObject *root = engine.rootObjects()[0]; // yet unused
    
       QQmlComponent* component = new QQmlComponent(&engine, QUrl(QStringLiteral("qrc:/ElementVariable.qml")));
        QQuickItem *item = qobject_cast<QQuickItem*>(component->create());
    
        qDebug()<< item->setProperty("text", "myNewText");  //returns true
        qDebug()<<item->setProperty("visible", true); //returns true
    
        engine.rootContext()->setContextProperty("EquationComponent", QVariant::fromValue<QQmlComponent*>(component));
     
        return app.exec();
    }
    

    main.qml:

    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        Component {
            id: emptyComponent
            Item {
            }
        }
        Loader {
            objectName: "equationLoader"
            sourceComponent: typeof EquationComponent !== "undefined" ? EquationComponent : emptyComponent;
            width: childrenRect.width
            height: childrenRect.height
        }
    }
    

    ElementVariable.qml:

    import QtQuick 2.0
    
    Rectangle {
        property alias text: textItem.text
        width: childrenRect.width
        height: childrenRect.height
        Text {
            id: textItem
            width: implicitWidth + 10
            height: implicitHeight
            text: "textUnchanged"  // this I want to change
            verticalAlignment: Text.AlignVCenter
            horizontalAlignment: Text.AlignHCenter
        }
    }
    

    Result: I do see the element, but I don't see the text that is set in the main.cpp, I only see the Component's default text.

    Any ideas?


  • Qt Champions 2017

    @SeDi said in Creating and changing qml objects from c++:

    I can't see the properties set by c++.

    Where are you setting the properties in C++ which you would like see on QML ? Atleast I don't see that code here.



  • @dheerendra - thanks for your reply!

    I set it right before the end of the main.cpp. It is a bit "hidden" because I have prepended it with qDebug()<<

        qDebug()<< item->setProperty("text", "myNewText");  //returns true
        qDebug()<<item->setProperty("visible", true); //returns true
    

  • Qt Champions 2017

    Here you are changing the properties of object called item. This object is not going to change your component.



  • @dheerendra - oh, I see. Thank you for your time and effort!

    I have changed

    engine.rootContext()->setContextProperty("EquationComponent", QVariant::fromValue<QQmlComponent*>(component));
    

    into

    engine.rootContext()->setContextProperty("EquationComponent", QVariant::fromValue<QQuickItem*>(item));
    

    but I get the error:
    "qrc:/main.qml:17:26: Unable to assign ElementVariable_QMLTYPE_2 to QQmlComponent"

    This seems understandable - it's called sourceComponent: after all.

    Having reverted the above idea (back to setting the component, not the item) I have also tried to set the properties on the component - doesn't work either:

        qDebug()<< component ->setProperty("text", "myNewText");  //returns false
        qDebug()<<component ->setProperty("visible", true); //returns false
    

    It appears that I might have a misconception about Components/Items and that I lack sufficient knowledge about the Loader QML element.

    • is a Component more like a template / a class?
    • is an Item its realisation, like an actual object?
    • How can I "force-feed" the Loader from c++ with a specific Object created from there?

  • Qt Champions 2017

    Yes component is like class. Once done you can’t change. you can change properties of object. You can specify the properties while loading. You can check documentation for this.



  • Thank you very much! That solved it. The creation process is being done automatically by the Loader in QML. It didn't make sense to make a second and unrelated "component->create()" in c++. I have to set the Component first and then get the Item from the Loader via property("item") afterwards.

    Here's the code involved:

    loader->setProperty("sourceComponent", QVariant::fromValue<QQmlComponent*>(component));
    QQuickItem* loaderItem = qvariant_cast<QQuickItem*>(loader->property("item"));
    loaderItem->setProperty("text", "myNewText");
    

  • Qt Champions 2017

    NO need to set the property from C++ by getting item. You can do something like
    Loader { sourceComponent: EquationComponent; text: "PthinkS" }


Log in to reply