You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在QAbstractProxyModel中使用Map替代List并在QML视图中应用

在QAbstractProxyModel中使用Map存储数据并适配QML视图

要实现继承自QAbstractProxyModel的类以Map为数据存储,并在QML的Repeater、ListView等视图中使用,核心是重写代理模型的关键方法,将Map的键值对映射为模型的行数据,并正确通知视图数据变化。以下是完整实现步骤和示例代码:

一、C++代理模型实现

1. 头文件定义

#ifndef MAPPROXYMODEL_H
#define MAPPROXYMODEL_H

#include <QAbstractProxyModel>
#include <QVariantMap>

class MapProxyModel : public QAbstractProxyModel
{
    Q_OBJECT
    Q_PROPERTY(QVariantMap map READ map WRITE setMap NOTIFY mapChanged)

public:
    explicit MapProxyModel(QObject *parent = nullptr);

    QVariantMap map() const;
    void setMap(const QVariantMap &newMap);
    // 支持动态插入单个键值对(可选)
    Q_INVOKABLE void insertValue(const QString &key, const QVariant &value);

    // 重写代理模型纯虚函数
    QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
    QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;

    // 重写模型核心方法
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
    QModelIndex parent(const QModelIndex &child) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    QHash<int, QByteArray> roleNames() const override;

signals:
    void mapChanged();

private:
    QVariantMap m_map;
    QList<QString> m_keys; // 保存键的顺序,保证视图显示稳定
};

#endif // MAPPROXYMODEL_H

2. 源文件实现

#include "mapproxymodel.h"

MapProxyModel::MapProxyModel(QObject *parent) : QAbstractProxyModel(parent)
{
}

QVariantMap MapProxyModel::map() const
{
    return m_map;
}

void MapProxyModel::setMap(const QVariantMap &newMap)
{
    if (m_map == newMap)
        return;

    beginResetModel();
    m_map = newMap;
    m_keys = m_map.keys();
    endResetModel();
    emit mapChanged();
}

void MapProxyModel::insertValue(const QString &key, const QVariant &value)
{
    if (m_map.contains(key)) {
        m_map[key] = value;
        int row = m_keys.indexOf(key);
        emit dataChanged(index(row, 0), index(row, 0), {Qt::DisplayRole, Qt::UserRole + 2});
        return;
    }

    beginInsertRows(QModelIndex(), m_keys.size(), m_keys.size());
    m_map[key] = value;
    m_keys.append(key);
    endInsertRows();
}

QModelIndex MapProxyModel::mapToSource(const QModelIndex &proxyIndex) const
{
    // 本代理不依赖源模型,返回无效索引
    return QModelIndex();
}

QModelIndex MapProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
{
    return QModelIndex();
}

int MapProxyModel::rowCount(const QModelIndex &parent) const
{
    return parent.isValid() ? 0 : m_keys.size();
}

int MapProxyModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return 1; // 按行展示键值对,可根据需求改为2(分键、值两列)
}

QModelIndex MapProxyModel::index(int row, int column, const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();
    return createIndex(row, column, (void*)&m_keys[row]);
}

QModelIndex MapProxyModel::parent(const QModelIndex &child) const
{
    Q_UNUSED(child);
    return QModelIndex(); // 列表结构,无父节点
}

QVariant MapProxyModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || index.row() >= m_keys.size())
        return QVariant();

    const QString &key = m_keys[index.row()];
    const QVariant &value = m_map[key];

    switch (role) {
    case Qt::DisplayRole:
        return QString("%1: %2").arg(key).arg(value.toString());
    case Qt::UserRole + 1:
        return key;
    case Qt::UserRole + 2:
        return value;
    default:
        return QVariant();
    }
}

QHash<int, QByteArray> MapProxyModel::roleNames() const
{
    QHash<int, QByteArray> roles = QAbstractProxyModel::roleNames();
    roles[Qt::UserRole + 1] = "key";
    roles[Qt::UserRole + 2] = "value";
    return roles;
}

3. 注册QML类型

在main.cpp中注册自定义模型,让QML可以访问:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "mapproxymodel.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<MapProxyModel>("com.example.models", 1, 0, "MapProxyModel");

    QQmlApplicationEngine engine;
    engine.load(QUrl(u"qrc:/main.qml"_qs));

    return app.exec();
}

二、QML视图使用示例

import QtQuick 2.15
import QtQuick.Window 2.15
import com.example.models 1.0

Window {
    width: 640
    height: 480
    visible: true
    title: "Map Proxy Model Demo"

    // 实例化C++模型
    MapProxyModel {
        id: cppMapModel
        map: {
            "name": "Alice",
            "age": 25,
            "city": "New York"
        }
    }

    // 定义委托组件
    Component {
        id: delegateComponent
        Row {
            spacing: 15
            padding: 10
            width: parent.width
            border.width: 1
            border.color: "#e0e0e0"

            Text {
                text: "键: " + model.key
                font.bold: true
                color: "#333"
            }
            Text {
                text: "值: " + model.value
                color: "#666"
            }
        }
    }

    // 使用Repeater展示数据
    Repeater {
        anchors.fill: parent
        anchors.margins: 20
        model: cppMapModel
        delegate: delegateComponent
    }

    // 动态添加数据示例(可选)
    Timer {
        interval: 3000
        running: true
        onTriggered: cppMapModel.insertValue("gender", "Female")
    }
}

关键说明

  • 键顺序稳定:用QList<QString>保存Map的键,解决QVariantMap无序的问题,保证视图显示顺序固定。
  • 数据变化通知:替换整个Map时用beginResetModel()和endResetModel();修改单个键值对时用dataChanged(),动态插入用beginInsertRows(),让视图高效更新。
  • 角色映射:重写roleNames()定义key和value角色,QML中可直接通过model.key、model.value访问数据。

内容的提问来源于stack exchange,提问作者Cypress

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 07:35:11