如何从QML Repeater访问QAbstractTableModel中的数据
用QAbstractTableModel在QML Repeater中显示键值对数据
折腾过QML模型绑定的人都懂,一开始确实容易绕晕,不过用QAbstractTableModel来做是很规范的方案,我帮你梳理清楚关键步骤,把这个问题解决掉。
第一步:先把你的DataBridge模型补全
首先得确保你的模型类实现了QAbstractTableModel的核心方法,尤其是角色名重写——这是QML能正确访问数据的关键,很多人在这里踩坑。
databridge.h
#ifndef DATABRIDGE_H #define DATABRIDGE_H #include <QAbstractTableModel> #include <QVector> #include <QPair<QString, QString>> class DataBridge : public QAbstractTableModel { Q_OBJECT public: explicit DataBridge(QObject *parent = nullptr); // 必须实现的模型基础方法 int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; // 重写角色名,让QML能通过友好名称访问数据 QHash<int, QByteArray> roleNames() const override; // 加个测试用的添加数据方法,方便验证 Q_INVOKABLE void addKeyValue(const QString &name, const QString &value); private: QVector<QPair<QString, QString>> m_keyValueList; // 存储键值对数据 // 自定义数据角色 enum Roles { NameRole = Qt::UserRole + 1, ValueRole }; }; #endif // DATABRIDGE_H
databridge.cpp
#include "databridge.h" DataBridge::DataBridge(QObject *parent) : QAbstractTableModel(parent) { // 先塞点测试数据,方便一运行就看到效果 m_keyValueList.append({"分辨率宽度", "1920"}); m_keyValueList.append({"分辨率高度", "1080"}); m_keyValueList.append({"系统版本", "Windows 11"}); } int DataBridge::rowCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; return m_keyValueList.size(); } int DataBridge::columnCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; return 2; // 两列:名称+值 } QVariant DataBridge::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() >= m_keyValueList.size()) return QVariant(); const auto ¤tPair = m_keyValueList[index.row()]; switch (role) { case NameRole: return currentPair.first; case ValueRole: return currentPair.second; case Qt::DisplayRole: // 兼容按列索引访问的场景 return index.column() == 0 ? currentPair.first : currentPair.second; default: return QVariant(); } } QHash<int, QByteArray> DataBridge::roleNames() const { QHash<int, QByteArray> roles; roles[NameRole] = "name"; roles[ValueRole] = "value"; return roles; } void DataBridge::addKeyValue(const QString &name, const QString &value) { // 必须调用这些begin/end方法通知视图数据变化,否则QML不会刷新 beginInsertRows(QModelIndex(), m_keyValueList.size(), m_keyValueList.size()); m_keyValueList.append({name, value}); endInsertRows(); }
第二步:把模型传递给QML
在主函数里,你需要把模型注册到QML上下文,让QML能访问到它:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include "databridge.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); // 注册模型类,允许在QML中直接实例化(可选,也可以直接传实例) qmlRegisterType<DataBridge>("com.myapp.models", 1, 0, "DataBridge"); QQmlApplicationEngine engine; // 创建模型实例,设置为全局上下文属性,方便QML直接用 DataBridge *dataModel = new DataBridge(); engine.rootContext()->setContextProperty("myKeyValueModel", dataModel); const QUrl url(u"qrc:/main.qml"_qs); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); }
第三步:在QML中用Repeater渲染数据
现在就可以在QML里通过Repeater遍历模型了,推荐用角色名访问,更直观:
import QtQuick 2.15 import QtQuick.Window 2.15 import com.myapp.models 1.0 Window { width: 600 height: 400 visible: true title: qsTr("键值对数据展示") Column { anchors.fill: parent anchors.margins: 20 spacing: 12 Text { text: "系统参数列表" font.pixelSize: 20 font.bold: true } // 用Repeater遍历模型的每一行 Repeater { model: myKeyValueModel // 直接用上下文里的模型实例 Row { spacing: 30 width: parent.width Text { text: model.name // 通过角色名获取名称 font.bold: true color: "#333" } Text { text: model.value // 通过角色名获取值 color: "#666" } } } // 加个按钮测试动态添加数据 Button { text: "添加参数" onClicked: myKeyValueModel.addKeyValue("CPU占用", "25%") } } }
关键提醒
- 一定要重写
roleNames():QML默认只识别Qt自带的角色(比如DisplayRole),自定义角色必须通过这个方法暴露给QML,否则model.name这种写法会无效。 - 数据变化要通知视图:添加/删除/修改数据时,必须调用
beginInsertRows()、endInsertRows()这类方法,否则QML界面不会同步更新。 - 避免直接操作底层数据:不要在外部直接修改
m_keyValueList,最好通过模型提供的方法(比如addKeyValue)来操作,这样能保证数据变化被正确通知。
内容的提问来源于stack exchange,提问作者admiral142




