如何从C++访问嵌套的 QML 对象

How to access a nested QML object from C++?

本文关键字:QML 对象 嵌套 访问 C++      更新时间:2023-10-16

这是一个可重现的例子:

主.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();
        }
    }
}

主.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();
}

我希望访问property QML Item的某个text。上述方法未产生所需的结果。

怎么办?

根据您的个人喜好,您有两种方法(至少)可以完成此操作。

QML代码扩展

您可以向根项添加属性别名,如下所示:

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++代码扩展

由于 QML 项是QObject的,因此您也可以显式查找子项,就像在C++ QObject层次结构中一样。代码将是这样的:

#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();
}

但是,这意味着您需要将objectName: "SomeNumberText"行添加到 qml 文件中的文本子项。

在这里你可以找到一个递归方法,通过objectName和从QQmlApplicationEngine::rootObjects()开始寻找QML项目:

////
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);
}

这有什么用例? 最好只将 [text, someNumber] 结构或对象视为模型。 然后,您只需要找到模型对象。或者,您可以在C++端创建模型对象,并将其设置在 QML 上下文中。 您可以在 QML 中访问模型及其嵌套属性:

Text {
        text: model.text
        property int someNumber: model.someNumber
    }