QAbstractItemModel 顶层的 QML 委托

QML delegate for top layer of QAbstractItemModel

我有一个两层 QAbstractItemModel 派生的自定义树模型,我想在 QML 中显示它。有什么方法可以为模型的每一层分配不同的代表吗?

p.s。首选解决方案意味着不更改模型

编辑:您可以假设模型看起来有点像这样:

// testmodel.h

#ifndef TESTMODEL_H
#define TESTMODEL_H

#include <QAbstractItemModel>

class TestModel : public QAbstractItemModel
{
    Q_OBJECT
public:
    QModelIndex index(int row, int column, const QModelIndex &parent = {}) const;
    QModelIndex parent(const QModelIndex &child) const;
    QModelIndex sibling(int row, int column, const QModelIndex &index) const;

    int rowCount(const QModelIndex &index = {}) const;
    int columnCount(const QModelIndex & = {}) const { return 1; }

    QVariant data(const QModelIndex &, int) const { return {}; }
    bool setData(const QModelIndex &, const QVariant &, int) { return false; }

    bool insertRows(int from, int count, const QModelIndex &parent);
    bool removeRows(int from, int count, const QModelIndex &parent);

private:
    QVector<int> _sizes;
};

#endif // TESTMODEL_H


// testmodel.cpp

#include "testmodel.h"

constexpr uintmax_t defId = -1;

QModelIndex TestModel::index(int row, int column, const QModelIndex &parent) const {
    return createIndex(row, column, parent.isValid() ? parent.row() : defId);
}

QModelIndex TestModel::parent(const QModelIndex &child) const {
    auto id = child.internalId();
    if (id == defId)
        return {};
    return createIndex(id, 0, defId);
}

QModelIndex TestModel::sibling(int row, int column, const QModelIndex &index) const {
    if (!index.isValid())
        return {};
    return createIndex(row, column, index.internalId());
}

int TestModel::rowCount(const QModelIndex &index) const {
    if (!index.isValid())
        return _sizes.size();

    if (index.internalId() != defId)
        return 0;

    int row = index.row();
    return row >= _sizes.size() ? 0 : _sizes[index.row()];
}

bool TestModel::insertRows(int from, int count, const QModelIndex &parent) {
    if (count <= 0 || from < 0)
        return false;

    auto to = from + count - 1;

    if (!parent.isValid()) {
        if (from > _sizes.size())
            return false;

        beginInsertRows(parent, from, to);
        _sizes.insert(from, count, 0);
        endInsertRows();
        return true;
    }

    if (parent.internalId() != defId)
        return false;

    int row = parent.row();
    if (row >= _sizes.size())
        return false;

    if (from > _sizes[row])
        return false;

    beginInsertRows(parent, from, to);
    _sizes[row] += count;
    endInsertRows();
    return true;
}

bool TestModel::removeRows(int from, int count, const QModelIndex &parent) {
    if (count <= 0 || from < 0)
        return false;

    auto to = from + count - 1;

    if (!parent.isValid()) {
        if (to >= _sizes.size())
            return false;
        beginRemoveRows(parent, from, to);
        _sizes.remove(from, count);
        endRemoveRows();
        return true;
    }

    if (parent.internalId() != defId)
        return false;

    int row = parent.row();
    if (row >= _sizes.size())
        return false;

    if (to >= _sizes[row])
        return false;

    beginRemoveRows(parent, from, to);
    _sizes[row] -= count;
    endRemoveRows();
    return true;
}

我实际上是在寻找 DelegateModel 组件(或 VisualDataModel)。列出一个简单示例,将模型的顶层显示为红色行,由底层的蓝色矩形填充:

ListView {
    id: view
    anchors.fill: parent

    model: DelegateModel {
        model: testModel // testModel is a tree model as context property

        delegate: Rectangle {
            width: win.width
            height: 30
            color: "red"
            border.color: "black"

            ListView {
                anchors.fill: parent
                orientation: Qt.Horizontal

                model: DelegateModel {
                    model: testModel
                    rootIndex: view.model.modelIndex(index, 0)

                    delegate: Rectangle {
                        height: 30
                        width: height
                        color: "blue"
                        border.color: "black"
                    }
                }
            }
        }
    }
}