You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何从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 &currentPair = 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%")
        }
    }
}

关键提醒

  1. 一定要重写roleNames():QML默认只识别Qt自带的角色(比如DisplayRole),自定义角色必须通过这个方法暴露给QML,否则model.name这种写法会无效。
  2. 数据变化要通知视图:添加/删除/修改数据时,必须调用beginInsertRows()endInsertRows()这类方法,否则QML界面不会同步更新。
  3. 避免直接操作底层数据:不要在外部直接修改m_keyValueList,最好通过模型提供的方法(比如addKeyValue)来操作,这样能保证数据变化被正确通知。

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

火山引擎 最新活动