如何在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
相关产品推荐
相关产品推荐

