【问题标题】:How to access a nested QML object from C++?如何从 C++ 访问嵌套的 QML 对象?
【发布时间】:2014-01-15 01:19:03
【问题描述】:

这是一个可重现的例子:

ma​​in.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();
        }
    }
}

ma​​in.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 的某个编号的 property。 上述方法没有产生预期的结果。

怎么做?

【问题讨论】:

  • 为什么不是属性别名?
  • @LaszloPapp 不明白,请解释一下。
  • 属性别名 mytext: t1.text 用于根项,或 'QObject *object = object->findChild("t1");`
  • 在 QML 中,您将 Text 命名为“t1”,但在 C++ 中,您将其访问为“ti”。错字?
  • @StefanMonov 这可能是错字。感谢您指出。

标签: c++ qt qml qtquick2 qtcore


【解决方案1】:

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

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 文件中的 Text 子项。

【讨论】:

  • findChild 搜索具有给定 objectName 属性值的对象,该属性值不等于 QML 的 id。如果我们假设不应修改 QML 代码,那不是解决方案。否则,我们必须在 QML 中添加objectName: "tr1"
  • @leemes:你是对的而且太快了。我忙于添加更多代码并修复初始版本中的错误。 ;-)
  • 您知道使用id 查找QML 项目的任何方法吗?这将允许我们在不添加 objectName 的情况下查找项目。
  • @pedromateo:据我所知,“id”通常是一个 qml 属性,很自然,它不适用于所有 QObjects。现在,一些 QML C++ 类可能会有一些特定于 qml 的子查找器算法,但我不确定它是否足够常见的用例。
  • @Ipapp:你是对的。我读到id 确实只存在于 QML 层,而不存在于 QObject 级别。
【解决方案2】:

在这里,您可以找到一种递归方法,通过objectName 查找 QML 项目并从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);
}

【讨论】:

  • 为什么不为QQmlApplicationEngine::rootObjects() 中的每个项目调用QObject::findChild?默认情况下是递归的。好像你在重新发明轮子。
  • 不,不是。事实上,正是它不递归的原因把我带到了这里。
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-17
    • 1970-01-01
    • 1970-01-01
    • 2021-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多