How can I access my Window object properties from C++ while using QQmlApplicationEngine?

24,722

Turning my comment into a proper answer: this is usually done by two methods:

  • Get the root object of your QML scene through a view if you use QQuickView or just the QQmlApplicationEngine directly.

  • This next step can be omitted for root objects, but for "qml objects" in general, you will need to have the objectName property set and then you can find any children with the following method:

QList QObject::findChildren(const QString & name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const

C++ side

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QDebug>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:///main.qml")));

    // Step 1: get access to the root object
    QObject *rootObject = engine.rootObjects().first();
    QObject *qmlObject = rootObject->findChild<QObject*>("mainWindow");

    // Step 2a: set or get the desired property value for the root object
    rootObject->setProperty("visible", true);
    qDebug() << rootObject->property("visible");

    // Step 2b: set or get the desired property value for any qml object
    qmlObject->setProperty("visible", true);
    qDebug() << qmlObject->property("visible");

    return app.exec();
}

See the documentation for property set and get in the official documentation:

bool QObject::setProperty(const char * name, const QVariant & value)

and

QVariant QObject::property(const char * name) const

Good, we are now more or less done on the C++ side.

QML Side

You will also need to have the objectName property of your qml objects set if you wish to access more than just the root item as follows:

import QtQuick 2.2
import QtQuick.Window 2.1

Window {
    id: mainWindow
    objectName: "mainWindow"
    ...
}

This can be similarly done for any QML object. The key is "objectName" in here. You could omit that for the root object as the C++ side gets the root object directly, but since you are referring to QML objects in your question, I assume that you would like to solve it in general. Once you wish to do the same for any QML object, i.e. including children, you will need to use the objectName property.

Share:
24,722
MrKatSwordfish
Author by

MrKatSwordfish

Updated on April 01, 2020

Comments

  • MrKatSwordfish
    MrKatSwordfish about 4 years

    I've been trying to learn QtQuick for GUI creation, but I've been having a hard time understanding how to interact with QML objects from the C++ part of my test program.

    Here's my simple QML file:

    import QtQuick 2.2
    import QtQuick.Window 2.1
    
    Window {
        id: mainWindow
        visible: true
        width: 800
        height: 800
        color: "#FFFF0000"
    
        MouseArea {
            anchors.fill: parent
            onClicked: Qt.quit()
        }
    
        Rectangle {
            id: testRect
            width: 100
            height: 100
            anchors.centerIn: parent
            color: "#FF0000FF"
        }
    }
    

    Here's the basic C++ file that came with it (auto-generated by QtCreator):

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
    
        return app.exec();
    }
    

    My issue is that I have no idea how to gain access to my 'Window' QML object, and as a result, I'm unable to alter any of its properties or the properties of its children! This part of the QtQuick documentation shows two methods of accessing QML objects from within C++ code, but neither of them seem to apply to this 'QQmlApplicationEngine' loading scheme.. I've also seen people use things like 'QApplicationViewer' and 'QDeclaritiveView', but I can't seem to find those in the official documentation at all..

    I'm getting really frustrated with QtQuick; the 'simplicity' of QML seems to be lost in a sea of conflicting documentation and convoluted interface between C++ and QML. Is there anyway for me to access my QML objects while using the QQmlApplicationEngine method? I've tried using 'QuickView', but it doesn't seem to work well with Window QML objects..? Is QQmlApplicationEngine only useful for QML-only applications in a single file? So far, every piece of documentation and tutorial I've read has shown something different..

    Any help or clarification would be appreciated. Ideally I'd like to know how to access and modify QML objects (like 'mainWindow', 'testRect', and other objects in other files) via my C++ code.

  • MrKatSwordfish
    MrKatSwordfish about 10 years
    Thanks! Seems like that might do the trick, I'll mess around with it soon. A bit of a followup, but.. Do you think I should be using QQmlEngine on its own instead of the QQmlApplicationEngine derived class? What about QQuickView? I'm finding it hard to understand the differences/reasons behind each one of these 'contexts' (QQmlEngine, QQmlApplicationEngine, QQuickView, etc.).. I'm interested in the OpenGL backend w/ hardware accelleration, so I don't want to overlook anything important. Thanks again for the help Laszlo!
  • László Papp
    László Papp about 10 years
    @MrKatSwordfish: for this simple case, I would probably use QQuickView with QQmlEngine, yeah. Let me know whether this solution works for you.
  • Hyndrix
    Hyndrix over 9 years
    Thanks for sharing the solution. If you are using remote Qml then it is better to access rootobject form the signal: objectCreated(QObject* rootObject, QUrl url)
  • Sami Ben
    Sami Ben about 7 years
    The downside is that there is no intellisense, is there any new way to get the QObject as a proper type with proper intellisense?
  • Liviu
    Liviu about 7 years
    But the "id" property is used for what then?