从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(); }
问题根源分析
- 卡顿崩溃原因:无限制添加数据会让模型行数持续增长,
VXYModelMapper需要同步所有历史数据,内存占用和UI渲染压力剧增,最终导致崩溃。 - 图表停止更新原因:修改后的
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
相关产品推荐
相关产品推荐

