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

如何用C++ Vector追加列表模型?Qt/QML新手同步C++列表至ListModel

解决你的C++ Vector与Qt/QML ListModel交互问题

嘿,我来帮你搞定这两个问题~ 针对你提到的需求,我分两种场景给你具体的实现方案,都是实际项目里常用的方法:

一、如何用C++的Vector追加数据到QML的ListModel?

这里有两种常用思路,你可以根据场景选择:

方案1:C++返回QVariantList,QML侧手动追加

这种方式简单直接,适合数据量不大、不需要频繁更新的场景:

  1. 第一步:写C++数据提供类
    把Vector里的数据转换成QML能识别的QVariantList,用Q_INVOKABLE标记方法让QML可以调用:

    #include <QObject>
    #include <vector>
    #include <QVariantList>
    #include <tuple>
    
    class DataProvider : public QObject
    {
        Q_OBJECT
    public:
        explicit DataProvider(QObject *parent = nullptr) : QObject(parent) {}
    
        // 把Vector数据转成QVariantList返回给QML
        Q_INVOKABLE QVariantList getVectorData() {
            // 模拟你的Vector数据
            std::vector<std::tuple<int, double, double>> vecData = {
                {4, 3.14, 2.71},
                {5, 1.11, 0.01},
                {6, 0.5, 0.8}
            };
    
            QVariantList result;
            for (const auto& item : vecData) {
                QVariantMap itemMap;
                itemMap["hs"] = std::get<0>(item);
                itemMap["tp"] = std::get<1>(item);
                itemMap["dp"] = std::get<2>(item);
                result.append(itemMap);
            }
            return result;
        }
    };
    
  2. 第二步:在main.cpp注册类到QML上下文
    让QML能访问这个C++类:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "dataprovider.h"
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        DataProvider provider;
        // 把实例暴露给QML,命名为dataProvider
        engine.rootContext()->setContextProperty("dataProvider", &provider);
    
        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();
    }
    
  3. 第三步:QML侧调用方法并追加数据
    给你的ListView加个按钮,点击后获取C++数据并追加到ListModel:

    Rectangle {
        id: container
        width: 500; height: 400
    
        ListModel {
            id: environmentModel
            ListElement { hs: 2 tp: 2.45 dp: 2.45 }
            ListElement { hs: 1 tp: 2.45 dp: 2.45 }
            ListElement { hs: 3 tp: 2.45 dp: 2.45 }
        }
    
        Component {
            id: environmentDelegate
            Text {
                text: "hs: " + hs + ", tp: " + tp + ", dp: " + dp
                width: container.width
                padding: 10
                border.width: 1
            }
        }
    
        ListView {
            anchors.fill: parent
            model: environmentModel
            delegate: environmentDelegate
        }
    
        Button {
            text: "追加C++ Vector数据"
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            onClicked: {
                let newData = dataProvider.getVectorData();
                // 遍历数据,逐个追加到ListModel
                for (let item of newData) {
                    environmentModel.append(item);
                }
            }
        }
    }
    

方案2:用QAbstractListModel(推荐用于动态数据场景)

如果你的数据需要频繁更新、或者数据量较大,Qt官方更推荐用QAbstractListModel实现MVVM模式,数据和视图分离,性能更好:

  1. 第一步:实现自定义ListModel类
    这个类继承自QAbstractListModel,内部维护Vector数据,重写必要的方法:

    #include <QAbstractListModel>
    #include <vector>
    #include <tuple>
    
    class EnvironmentModel : public QAbstractListModel
    {
        Q_OBJECT
        // 定义数据角色,对应QML里的hs/tp/dp字段
        enum EnvironmentRoles {
            HsRole = Qt::UserRole + 1,
            TpRole,
            DpRole
        };
    
    public:
        explicit EnvironmentModel(QObject *parent = nullptr) : QAbstractListModel(parent) {
            // 初始化默认数据
            m_data = {
                {2, 2.45, 2.45},
                {1, 2.45, 2.45},
                {3, 2.45, 2.45}
            };
        }
    
        // 返回数据行数
        int rowCount(const QModelIndex &parent = QModelIndex()) const override {
            Q_UNUSED(parent);
            return m_data.size();
        }
    
        // 返回指定行、角色的数据
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
            if (!index.isValid() || index.row() >= m_data.size())
                return QVariant();
    
            const auto& item = m_data[index.row()];
            switch (role) {
            case HsRole:
                return std::get<0>(item);
            case TpRole:
                return std::get<1>(item);
            case DpRole:
                return std::get<2>(item);
            default:
                return QVariant();
            }
        }
    
        // 注册角色名称,让QML能识别hs/tp/dp
        QHash<int, QByteArray> roleNames() const override {
            QHash<int, QByteArray> roles;
            roles[HsRole] = "hs";
            roles[TpRole] = "tp";
            roles[DpRole] = "dp";
            return roles;
        }
    
        // 从Vector追加数据的方法
        Q_INVOKABLE void appendFromVector(const std::vector<std::tuple<int, double, double>>& newData) {
            // 通知QML开始插入数据
            beginInsertRows(QModelIndex(), m_data.size(), m_data.size() + newData.size() - 1);
            m_data.insert(m_data.end(), newData.begin(), newData.end());
            // 通知QML插入完成,自动更新视图
            endInsertRows();
        }
    
        // 模拟从外部获取数据的方法
        Q_INVOKABLE void fetchNewData() {
            std::vector<std::tuple<int, double, double>> newVec = {
                {4, 3.14, 2.71},
                {5, 1.11, 0.01}
            };
            appendFromVector(newVec);
        }
    
    private:
        std::vector<std::tuple<int, double, double>> m_data;
    };
    
  2. 第二步:注册为QML类型
    在main.cpp里把这个类注册成QML可以直接使用的类型:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "environmentmodel.h"
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        // 注册自定义模型到QML,命名空间com.example.models,版本1.0
        qmlRegisterType<EnvironmentModel>("com.example.models", 1, 0, "EnvironmentModel");
    
        QQmlApplicationEngine engine;
        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();
    }
    
  3. 第三步:QML侧使用自定义模型
    直接创建自定义模型实例,绑定到ListView,点击按钮触发C++的方法更新数据:

    import com.example.models 1.0
    
    Rectangle {
        id: container
        width: 500; height: 400
    
        // 使用自定义的C++模型
        EnvironmentModel {
            id: environmentModel
        }
    
        Component {
            id: environmentDelegate
            Text {
                text: "hs: " + hs + ", tp: " + tp + ", dp: " + dp
                width: container.width
                padding: 10
                border.width: 1
            }
        }
    
        ListView {
            anchors.fill: parent
            model: environmentModel
            delegate: environmentDelegate
        }
    
        Button {
            text: "获取C++新数据"
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            onClicked: {
                environmentModel.fetchNewData();
            }
        }
    }
    

二、针对你作为Qt/QML新手的额外提示

  • 如果你只是简单追加数据,方案1足够用;如果后续需要删除、修改数据或者实时同步,方案2的自定义模型是更长远的选择。
  • 注意Q_INVOKABLE的作用是让QML可以调用C的方法,也可以用信号槽来实现数据更新(比如C数据变化时发信号,QML接收后处理)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:36:53