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

从C++数据模型更新QML LineSeries ChartView遇卡顿与停止更新问题

QML ChartView 结合C++模型更新LineSeries的问题

我在QML中使用ChartView,尝试从C++数据模型更新数据时遇到两个问题:

  • 多模型场景下,应用会逐渐卡顿,约1分钟后崩溃
  • 限制只显示最新500个点后,图表在达到500个点时停止更新

QML代码片段

ChartView {
    id: dataChartView
    animationOptions: ChartView.NoAnimation
    theme: ChartView.ChartThemeDark
    antialiasing: true
    Layout.fillHeight: true
    Layout.fillWidth: true

    ValueAxis {
        id: axisXdata
        min: dataManager.xMin
        max: dataManager.xMax
    }

    ValueAxis {
        id: axisYdata
        min: 0
        max: 1
    }

    LineSeries {
        id:  dataLineSeries
        name: "Angle"
        axisX: axisXdata
        axisY: axisYdata
    }

    VXYModelMapper {
        id:  dataModelMapper
        model: dataManager.dataModel[data]
        series: dataLineSeries
        firstRow: 1
        xColumn: 0
        yColumn: 1
    }
}

C++ DataModel 定义

class DataModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    enum{
        NameRole,
        ValueRole
    };

    explicit DataModel(QObject *parent = nullptr);
    QHash<int, QByteArray> roleNames() const override;
    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
    int rowCount(const QModelIndex& parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    void setMaxSize(int maxSize);
    int maxSize() const;
    Q_INVOKABLE void addData(const QPointF& point);

public:
    void handleNewData(const QPointF& point);

private:
    QVector<QPointF> m_data;
    int m_ModelMaxSize;

signals:
    void newDataAdded(const QPointF& point);
};

原始addData实现(导致卡顿崩溃)

void MsclDataModel::addData(const QPointF &point)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_data.push_back(point);
    endInsertRows();
}

DataManager 数据生成逻辑

void DataManager::GeneratePoints()
{
    setXMin(QDateTime::currentDateTime().toMSecsSinceEpoch()); // 设置横轴最小最大值
    for(double t=0 ; ; t+=1)
       {
           double y = (1 + sin(t/10.0)) / 2.0;

        // 处理多个数据模型
           for(const auto& model : m_Models)
           {
               auto time = QDateTime::currentDateTime().toMSecsSinceEpoch();
               setXMax(qMax(m_xMax, time));
               model->handleNewData(QPointF(time, y));
           }
           std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

修改后的addData(导致图表停止更新)

void DataModel::addData(const QPointF &point)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    if(m_data.size() == 500)
    {
        m_data.erase(m_data.begin());
    }
    m_data.push_back(point);
    endInsertRows();
}

问题根源分析

  1. 卡顿崩溃原因:无限制添加数据会让模型行数持续增长,VXYModelMapper需要同步所有历史数据,内存占用和UI渲染压力剧增,最终导致崩溃。
  2. 图表停止更新原因:修改后的addData逻辑错误——在beginInsertRows后删除第一个元素,此时模型行数在删除后仍为500,插入新数据后还是500,且只触发了插入信号未触发删除信号,导致模型索引对应关系失效,VXYModelMapper无法识别数据变化。

正确实现方案

1. 修复固定窗口数据更新逻辑

要维护最新的N个点,需先触发删除旧数据的信号,再触发插入新数据的信号:

void DataModel::addData(const QPointF &point)
{
    const int maxSize = 500;
    bool needRemove = m_data.size() >= maxSize;
    if (needRemove) {
        // 删除第一个元素,通知模型
        beginRemoveRows(QModelIndex(), 0, 0);
        m_data.erase(m_data.begin());
        endRemoveRows();
    }
    // 插入新元素,通知模型
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_data.push_back(point);
    endInsertRows();
}

2. 保证线程安全

DataManager在子线程调用model->handleNewData,而QAbstractTableModel的状态修改必须在其所属线程(通常为主线程)执行,需通过队列连接确保addData在主线程运行:

void DataModel::handleNewData(const QPointF& point)
{
    QMetaObject::invokeMethod(this, "addData", 
                              Qt::QueuedConnection, 
                              Q_ARG(QPointF, point));
}

3. 优化坐标轴同步

删除旧数据后,横轴的xMin需要同步更新为当前模型第一个点的x值,确保图表窗口跟随最新数据移动:

// 在DataModel中添加获取当前最小x值的方法
qint64 currentXMin() const {
    return m_data.isEmpty() ? 0 : m_data.first().x();
}

然后在QML的axisXdata中绑定:

ValueAxis {
    id: axisXdata
    min: dataManager.dataModel[data].currentXMin
    max: dataManager.xMax
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 02:20:59