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

14

这是一个可重现的例子:

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

我希望访问QML Itemtext属性中的somenumber属性。

以上方法未能产生期望的结果。

怎么做?


1
为什么不使用属性别名? - László Papp
@LaszloPapp不理解,请解释。 - Aquarius_Girl
1
属性别名mytext:t1.text适用于根项,或者'QObject *object = object->findChild<QObject*>("t1");`。 - László Papp
在 QML 中,您将 Text 命名为 "t1",但在 C++ 中,您将其访问为 "ti"。打字错误吗? - Stefan Monov
@StefanMonov 可能是打错了。感谢指出。 - Aquarius_Girl
3个回答

11

根据个人喜好,您至少有两种方法可以完成这个任务。

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

然而,这意味着您需要在qml文件中的Text子项中添加objectName: "SomeNumberText"行。


findChild 搜索具有给定 objectName 属性值的对象,该属性值不等于 QML 的 id。如果我们假设 QML 代码不应被修改,那么这不是一个解决方案。否则,我们必须在 QML 中添加 objectName: "tr1" - leemes
1
@leemes:你说得对,而且速度也很快。我一直在忙于添加更多的代码和修复初始版本中的错误。;-) - László Papp
你知道通过使用id查找QML项的任何方法吗?这将允许我们在不添加objectName的情况下查找项目。 - pedromateo
据我所知,“id”通常是QML属性,因此自然而然地,它不适用于所有QObjects。现在,可能有一些QML C++类会有一些特定于qml的子元素查找算法,但我不确定它是否足够普遍。 - László Papp
@Ipapp:你说得对。我读到过 id 只存在于 QML 层,而不是 QObject 层级。 - pedromateo
pedromateo:QML的id属性是特殊的,不像其他属性。请参见http://qt-project.org/doc/qt-5/qtqml-syntax-propertybinding.html。您无法像访问其他属性一样(在QML或C++中),访问其值(解引用或读取它,如“foo = id”)。 - bootchk

2

在这里,您可以找到一种使用递归方法查找QML项的技巧,该方法从QQmlApplicationEngine::rootObjects()开始并按objectName进行匹配:

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

3
为什么不直接对QQmlApplicationEngine::rootObjects()中的每个项调用QObject::findChild呢?它默认是递归的。看起来你在重新发明轮子。 - Stefan Monov
1
不,不是这样的。实际上,它不是递归的本身才让我来到这里。 - Daniel Ziltener

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接