来自 QML 的索引处的访问列表

Posted

技术标签:

【中文标题】来自 QML 的索引处的访问列表【英文标题】:Access list at index from QML 【发布时间】:2019-04-23 08:53:37 【问题描述】:

在我的程序中,我有一个需要从 QML 访问的树状对象架构。我无法弄清楚如何创建Q_PROPERTY getter 函数,这将允许我访问我选择的索引处的项目。该函数在 C++ 部分如下所示:

/**
 * @brief   Risk object getter function.
 * @param   index: The index of the risk from the \ref m_risks container.
 * @return  Pointer to the risk object if \p index is valid. Otherwise 0.
 */
CRiskData* CVessel::getRisk(const int index)

    if (index >= m_risks.length())
        return nullptr;

    return m_risks[index];

但似乎这个QML Qt属性通信系统只允许一个没有输入参数的getter。我试图这样定义它:

Q_PROPERTY(CRiskData* risk READ getRisk)

我收到一个编译器错误,找不到匹配的函数:

moc_cvessel.cpp:122: error: no matching function for call to 'CVessel::getRisk()'
         case 0: *reinterpret_cast< CRiskData**>(_v) = _t->getRisk(); break;
                                                                   ^

所以 MOC 创建了没有输入参数的函数... 有没有办法解决?目标是能够以分层方式从 QML 端访问对象的每个元素。

【问题讨论】:

您可以使用Q_INVOKABLE 使其成为一个可以有参数的函数,但是,这对于绑定而言可能并不方便,但由于没有给出那部分代码,因此无法检查 @Amfasis 谢谢你的回答。我认为这会奏效,会尝试实施。 【参考方案1】:

看看你的问题,我认为你应该使用与 MVVM (https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel) 或 MVC 相关的东西。因此,您应该通过子类化QAbstractItemModel,创建您自己的 C++ 模型并暴露给 QML。在此模型中,在您的列表模型中创建一个Q_INVOKABLE 方法:

cvessel.hpp:

#ifndef CVESSEL_HPP
#define CVESSEL_HPP

#include <QAbstractItemModel>
#include <QList>
class CRiskData;

class CVessel: public QAbstractItemModel

    Q_OBJECT

    public:
        CVessel(QObject * parent = nullptr);
        Q_INVOKABLE CRiskData* getRisk(const int index);
        static void declareQML();

        // QAbstractItemModel subclassing & rest of the header

    protected:
        QList<CRiskData *> m_risks;
;

#endif    // CVESSEL_HPP

cvessel.cpp:

#include "cvessel.hpp"
#include <QQmlEngine>
#include "criskdata.hpp"

CVessel::CVessel(QObject * parent = nullptr) :
    QAbstractItemModel(parent),
    m_risks()


CRiskData* CVessel::getRisk(const int index);

    if (index >= m_risks.length())
        return nullptr;

    return m_risks[index];


void CVessel::declareQML() 
    qmlRegisterType<CVessel>("Bremen", 3, 14, "CVessel");


// Rest of implementation

RiskComponent.qml:

import QtQuick 2.12
import Bremen 3.14

Item 
    id: risk_component

    // ...

    TreeItem 
        id: the_tree
        model: CVessel 

        // ...
    

    // ...

    function usingARisk(riskIndex) 
        var risk = risk_component.the_tree.model.getRisk(riskIndex)

        // Using your risk on the QML side. For Example:
        console.log(qsTr("Risk level: %1").arg(risk.level))
    

    // ...


main.cpp:

#include <QApplication>
#include <QQmlApplicationEngine>
#include "criskdata.hpp"
#include "cvessel.hpp"

int main(int argc, char ** argv) 
    QApplication app(argc, argv);

    //...

    CRiskData::declareQML();    // Of course if you use it on the QML side.
    CVessel::declareQML();

    //...

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
    int res = engine.rootObjects().isEmpty() ? -1 : app.exec();

    //...

    return res;

有关模型子类化的更多信息,请查看 Qt 文档中的 the "Model/View Programming" page,尤其是 the "Model Subclassing Reference" section。

【讨论】:

你为什么在这里继承QAbstractItemModel?有必要吗? 我刚刚更新了我对您的评论问题的回答。 感谢您的更新。我的观点是,“to qml”曝光功能可以通过仅使用 Qobject 来实现。这就是为什么我问为什么要这样做。 对于“to QML”暴露,您必须:1°)子类QObject,2°)提供默认构造函数和3°)在main();入口点调用qmlRegisterType&lt;&gt;(); .欲了解更多信息,请查看:doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html 没错!这就是为什么我想知道最后使用了 QAbstra tItemModel 吗?

以上是关于来自 QML 的索引处的访问列表的主要内容,如果未能解决你的问题,请参考以下文章

每次需要访问特定索引处的元素时是不是可以重新排序数组?

如何从 QML 中的列表视图访问 currentItem 的角色?

使用 Python 从 QML 中动态创建的列表中访问数据

使用 QAbstractListModel 从 python 访问 QML 中的列表元素

访问列表的多个元素知道它们的索引

如何从另一个 QML 访问和控制 ListModel 的内容