如何从 QML 访问嵌套的 QStandardItemModel 的项目?

Posted

技术标签:

【中文标题】如何从 QML 访问嵌套的 QStandardItemModel 的项目?【英文标题】:How to access nested QStandardItemModel's items from QML? 【发布时间】:2021-08-18 06:42:17 【问题描述】:

背景

我有一个树状 QStandardItemModel,我想从 QML 访问它的项目。

这是在 C++ 端定义模型的方式:

后端.h

class Backend : public QObject

    Q_OBJECT
    Q_PROPERTY(QStandardItemModel *model READ model CONSTANT)
public:
    explicit Backend(QObject *parent = nullptr);

    QStandardItemModel *model() const;

private:
    QStandardItemModel *m_model;
;

backend.cpp

Backend::Backend(QObject *parent) :
    QObject(parent),
    m_model(new QStandardItemModel(this))

    auto *itemFirst = new QStandardItem(tr("First"));
    auto *itemSecond = new QStandardItem(tr("Second"));
    auto *subItem = new QStandardItem(tr("First_02"));

    subItem->appendRow(new QStandardItem("First_02_01"));

    itemFirst->appendRow(new QStandardItem(tr("First_01")));
    itemFirst->appendRow(subItem);
    itemFirst->appendRow(new QStandardItem(tr("First_03")));

    itemSecond->appendRow(new QStandardItem(tr("Second_00")));
    itemSecond->appendRow(new QStandardItem(tr("Second_01")));

    m_model->appendRow(itemFirst);
    m_model->appendRow(itemSecond);


QStandardItemModel *Backend::model() const

    return m_model;

模型在main.cpp 中导出到 QML,如下所示:

Backend backend;
QQmlApplicationEngine engine;

engine.rootContext()->setContextProperty("backend", &backend);
qmlRegisterUncreatableType<QStandardItemModel>("QStandardItemModel", 1, 0, "QStandardItemModel", "The model should be created in C++");

main.qml 中使用来自 QtQuick.Controls 1.4 的 TreeView,如下所示:

TreeView 
    anchors.fill: parent
    model: backend.model

    TableViewColumn 
        title: "Name"
        role: "display"
    

我得到了想要的结果,即所有项目都正确嵌套:

问题

当我尝试使用 RepeaterDelegateModel 手动迭代嵌套项时,如下所示:

ColumnLayout 
    anchors.fill: parent

    Repeater 
        model: backend.model

        Item 
            Layout.fillWidth: true
            Layout.fillHeight: true

            ColumnLayout 
                anchors.fill: parent

                Text 
                    color: "blue"
                    text: model.display
                

                Repeater 
                    model: DelegateModel 
                        model: backend.model
                        rootIndex: modelIndex(index)

                        Item 
                            Layout.fillWidth: true
                            Layout.fillHeight: true

                            ColumnLayout 
                                anchors.fill: parent

                                Text 
                                    color: "green"
                                    text: model.display
                                

                                Repeater 
                                    model: DelegateModel 
                                        model: backend.model
                                        rootIndex: modelIndex(index)

                                        Text 
                                            color: "red"
                                            text: model.display
                                        
                                    
                                
                            
                        
                    
                
            
        
    

主分支(用蓝色标记)和第一个嵌套级别(用绿色标记)的项目是正确的,但我在第二个嵌套级别(用红色标记)得到了错误的项目:

如何修复代码以在每个嵌套级别上正确迭代 QStandardItemModel 的项目?

【问题讨论】:

这段代码应该做什么? Repeater 里面Repeater 同款有什么意义? @folibis 的模型不一样,OP 正在使用DelegateModelrootIndex 属性通过更改引用父 QModelIndex 来获取嵌套的“子模型”。 @folibis,我尽量将我的问题表述得足够笼统,以避免将焦点从概念转移到手头的具体任务上。因此,我认为嵌套中继器是 QML 中走下特定路径并直观地描绘树状模型所持有的任何数据的唯一可能性(假设客户列表和每个客户购买的产品)。假设购买的产品是每个客户的子项目,而不是在其数据中,那么使用一个中继器 QML 只会给我客户。 【参考方案1】:

问题出在这两行:rootIndex: modelIndex(index)

index 是“父”模型的索引,但modelIndex(...) 是当前模型的方法。


我已经用这段(稍微修改过的)代码进行了尝试,并且成功了:

Repeater 
    model: DelegateModel 
        id: model1

        model: backend.model

        delegate: ColumnLayout
            Text 
                text: "Data: " + display
            
            Repeater 
                model: DelegateModel 
                    id: model2

                    model: backend.model
                    // 'index' comes from 'model1', so use the 'modelIndex' method from 'model1'
                    rootIndex: model1.modelIndex(index)

                    delegate: ColumnLayout
                        Text 
                            text: "- Data: " + display
                        
                        Repeater 
                            model: DelegateModel 
                                id: model3

                                model: backend.model
                                // 'index' comes from 'model2', so use the 'modelIndex' method from 'model2'
                                rootIndex: model2.modelIndex(index)

                                delegate: Text 
                                    text: "--  Data: " + display
                                
                            
                        
                    
                
            
        
    

【讨论】:

以上是关于如何从 QML 访问嵌套的 QStandardItemModel 的项目?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 PySide 访问 QML\QtQuick 控件?

如何从 C++ 访问特定 QML 控件的事件

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

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

如何从 C++ 访问 QML ListView 委托项目?

PyQt5 和 QML 中的嵌套 ListView