14

Here is a reproducible example:

main.qml


import QtQuick 2.0

Item {
    id : root
    width: 360
    height: 360

    Text {
        id : t1
        text: qsTr("Hello World")
        property int someNumber: 1000
        anchors.centerIn: parent
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }
}

main.cpp


#include <QtGui/QGuiApplication>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQmlProperty>
#include <QDebug>

#include "qtquick2applicationviewer.h"

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

    QtQuick2ApplicationViewer viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/untitled/main.qml"));
    viewer.showExpanded();

    QQmlEngine engine;
    QQmlComponent component(&engine, "qml/untitled/main.qml");
    QObject *object = component.create();

    qDebug() << "Property value:" << QQmlProperty::read(object, "root.t1.someNumber").toInt();

    return app.exec();
}

I wish to access the property somenumber of the text of the QML Item. The above method isn't producing the desired result.

How to do it?

Stefan Monov
  • 11,332
  • 10
  • 63
  • 120
Aquarius_Girl
  • 21,790
  • 65
  • 230
  • 411

3 Answers3

11

You have two ways (at least) to accomplish this depending on your personal preference.

QML code extension

You can add a property alias to the root item as follows:

import QtQuick 2.0

Item {
    id : root
    width: 360
    height: 360

    property alias mySomeNumber: t1.someNumber // This is the addition

    Text {
        id : t1
        text: qsTr("Hello World")
        property int someNumber: 1000
        anchors.centerIn: parent
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }
}

C++ code extension

Since the QML items are QObject, you can look for the children explicitly as well, just as you would do it in a C++ QObject hierarchy. The code would be something like this:

#include <QtGui/QGuiApplication>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQmlProperty>
#include <QDebug>

#include "qtquick2applicationviewer.h"

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

    QtQuick2ApplicationViewer viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/untitled/main.qml"));
    viewer.showExpanded();

    QQmlEngine engine;
    QQmlComponent component(&engine, "qml/untitled/main.qml");
    QObject *object = component.create();

    // This line is added

    QObject *childObject = object->findChild<QObject*>("SomeNumberText");

    // The following line is modified respectively

    qDebug() << "Property value:" << QQmlProperty::read(childObject, "someNumber").toInt();

    return app.exec();
}

However, this means you will need to add the objectName: "SomeNumberText" line to your Text child item in the qml file.

László Papp
  • 51,870
  • 39
  • 111
  • 135
  • `findChild` searches for an object with the given `objectName` property value, which is not equal to QML's `id`. If we assume that the QML code should not be modified, that's not a solution. Otherwise, we have to add `objectName: "tr1"` in QML. – leemes Dec 27 '13 at 12:47
  • 1
    @leemes: you are right _and_ too fast. I was busy with adding lotta more code and fixing bugs in the initial version. ;-) – László Papp Dec 27 '13 at 12:53
  • Do you know any way to find a QML item by using its `id`? This would allow us to find items without adding an `objectName`. – pedromateo Oct 23 '14 at 09:03
  • @pedromateo: as far as I know "id" is a qml property usually, so naturally, that would not work for all QObjects. Now, it might be possible that some QML C++ class will have some qml specific children finder algorithm, but I am not sure if it is common enough a use case. – László Papp Oct 23 '14 at 09:14
  • @Ipapp: you are right. I read that `id` does exist only in QML layer, and not at QObject level. – pedromateo Oct 24 '14 at 07:37
  • pedromateo: the QML id property is special, i.e. not like other properties. See http://qt-project.org/doc/qt-5/qtqml-syntax-propertybinding.html. You can't access its value (dereference, or read it, as in 'foo = id') like other properties, in QML or in C++. – bootchk Nov 30 '14 at 15:29
2

Here you can find a recursive method looking for a QML item by objectName and starting at QQmlApplicationEngine::rootObjects():

////
static QQuickItem* FindItemByName(QList<QObject*> nodes, const QString& name)
{
    for(int i = 0; i < nodes.size(); i++){
        // search for node
        if (nodes.at(i) && nodes.at(i)->objectName() == name){
            return dynamic_cast<QQuickItem*>(nodes.at(i));
        }
        // search in children
        else if (nodes.at(i) && nodes.at(i)->children().size() > 0){
            QQuickItem* item = FindItemByName(nodes.at(i)->children(), name);
            if (item)
                return item;
        }
    }
    // not found
    return NULL;
}

///
static QQuickItem* FindItemByName(QQmlApplicationEngine* engine, const QString& name)
{
    return FindItemByName(engine->rootObjects(), name);
}
pedromateo
  • 2,965
  • 1
  • 18
  • 19
  • 3
    Why not just call `QObject::findChild` for each item in `QQmlApplicationEngine::rootObjects()`? It's recursive by default. Seems like you're reinventing the wheel. – Stefan Monov Aug 29 '16 at 19:48
  • 1
    No, it's not. In fact, the very reason of it not being recursive is what brought me here. – Daniel Ziltener Aug 19 '18 at 15:02
0

What is the use case for this? It might be better to just treat the [text, someNumber] struct or object as the model. Then you only need to find the model object. Or you could create the model object on the C++ side and set it in the QML context. You could access the model and its nested properties in QML:

Text {
        text: model.text
        property int someNumber: model.someNumber
    }
bootchk
  • 1,926
  • 17
  • 14