备注1、动态增加/移除坐标系2、多段y轴共用同一个x轴3、x轴y轴数据同步当放大缩小表格时4、通过定时器0.5s更新一次数据源码下载地址 https://download.csdn.net/download/weixin_45074487/90592500也可参考下面文档大数据量刷新曲线一秒500000个数据点https://blog.csdn.net/weixin_45074487/article/details/144985133****亲感觉不错的话点个赞哦****话不多说上源码亲测可用1、左侧通用树形目录参考 https://blog.csdn.net/weixin_45074487/article/details/137081375一、项目中结合树形目录勾选框进行动态增加和删除勾选框通过定时器模拟数据进行显示connect(m_treeWidget, TreeDirectoryWidget::sig_itemCheckChange, this, WdtCustomChart::SlotItemChange); connect(m_data_timer, SIGNAL(timeout()), this, SLOT(SlotDataTimeOut())); void WdtCustomChart::SlotItemChange(QString id, bool check) { //根据树形目录勾选框是否勾选进行动态增加/移除坐标系 if (check) { auto rows m_plot-plotLayout()-rowCount(); QCPAxisRect* axisRect CreateQCPAxisRect(id); m_plot-plotLayout()-addElement(rows, 0, axisRect); UpdateSettingCommonXaXisx(); ConnectAllAxisx(true); } else { //移除该通道坐标及曲线 RemoveQCPAxisRect(id); UpdateSettingCommonXaXisx(); max 50; min 0; } m_plot-replot(); } void WdtCustomChart::SlotDataTimeOut() { static double key 0;; // 开始到现在的时间单位 QCPAxis* poAxisY NULL; for (auto pair : m_channel_plots.toStdMap()) { int value qrand() % 20; auto channel pair.first; auto graph pair.second; graph-addData(key,value); if (m_channel_axises.contains(channel)) { auto AxisRec m_channel_axises.value(channel); //QCPAxis* poAxisY AxisRec-axis(QCPAxis::atLeft); //y轴 //int upper (int)(poAxisY-range().upper); //if (upper value) // poAxisY-setRangeUpper(value 10); if (key 20) AxisRec-axis(QCPAxis::atBottom)-setRange(key, 20, Qt::AlignRight); } } key0.5; //绘图 m_plot-replot(); } static const QColor colors[] { Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta, Qt::gray, Qt::darkRed, Qt::darkGreen, Qt::darkBlue, Qt::darkCyan, };二、核心代码1、动态增加channel所对应的坐标系QCPAxisRect* WdtCustomChart::CreateQCPAxisRect(QString channel) { //channel代表坐标系id QCPAxisRect* axisRect new QCPAxisRect(m_plot, true); axisRect-setupFullAxesBox(true); axisRect-setRangeZoom(Qt::Horizontal | Qt::Vertical); QCPAxis* poAxisX axisRect-axis(QCPAxis::atBottom); //x轴 QCPAxis* poAxisY axisRect-axis(QCPAxis::atLeft); //y轴 poAxisX-setRange(0, 20); poAxisY-setRange(0, 50); axisRect-axis(QCPAxis::atTop)-setVisible(false); axisRect-axis(QCPAxis::atRight)-setVisible(false); poAxisX-grid()-setSubGridVisible(true); poAxisY-grid()-setSubGridVisible(true); axisRect-setAutoMargins(QCP::msRight | QCP::msLeft); axisRect-setMargins(QMargins(100, 0, 0, 0)); poAxisY-setPadding(5); // 这里的5是你想要的额外填充 poAxisY-setTickLabelPadding(10); // 这里的5是你想要的额外填充 poAxisY-setLabelPadding(10); // 这里的5是你想要的额外填充 poAxisX-setVisible(true); poAxisX-setLabel(Trans(时间(s))); poAxisY-rescale(true); //y轴自适应 //设置x轴y轴自由缩放 QListQCPAxis* aaxisField; aaxisField poAxisX; aaxisField poAxisY; axisRect-setRangeZoomAxes(aaxisField); poAxisY-setVisible(true); poAxisY-setLabel(Trans(通道) channel); auto poGraph m_plot-addGraph(poAxisX, poAxisY); QPen pen; pen.setColor(colors[qrand() % 10]); poGraph-setPen(pen); //下面这两行使得Y轴轴线总是对齐 axisRect-setAutoMargins(QCP::MarginSide::msLeft | QCP::MarginSide::msRight); m_channel_axises.insert(channel.toInt(), axisRect); m_channel_plots.insert(channel.toInt(), poGraph); return axisRect; }2、动态删除channel所对应的坐标系void WdtCustomChart::RemoveQCPAxisRect(QString channel) { if (m_channel_axises.contains(channel.toInt()) m_channel_plots.contains(channel.toInt())) { auto axes_rect m_channel_axises.value(channel.toInt()); auto graph_plot m_channel_plots.value(channel.toInt()); m_plot-plotLayout()-remove(axes_rect); m_plot-plotLayout()-simplify(); m_channel_axises.remove(channel.toInt()); m_channel_plots.remove(channel.toInt()); } }3、//多段y轴共用同一个x轴void WdtCustomChart::UpdateSettingCommonXaXisx() { auto elements m_plot-plotLayout()-elementCount(); for (int row 0; row elements; row) { QCPAxisRect* poRecti (QCPAxisRect*)m_plot-plotLayout()-element(row, 0); if (poRecti) { //布局中最后一个元素进行设置 if (row (elements - 1)) { poRecti-setMargins(QMargins(100, 0, 0, 40)); poRecti-axis(QCPAxis::atBottom)-setVisible(true); } else { poRecti-setMargins(QMargins(100, 0, 0, 0)); poRecti-axis(QCPAxis::atBottom)-setVisible(false); } } } }4、//当鼠标放大缩小上下移动时 多段y轴x轴同步void WdtCustomChart::ConnectAllAxisx(bool on) { auto elements m_plot-plotLayout()-elementCount(); for (int i 0; i elements; i) { QCPAxisRect* poRecti (QCPAxisRect*)m_plot-plotLayout()-element(i, 0); for (int j 0; j elements; j) { QCPAxisRect* poRectj (QCPAxisRect*)m_plot-plotLayout()-element(j, 0); if (poRectj poRecti i!j) { connect(poRecti-axis(QCPAxis::atBottom), QOverloadconst QCPRange::of(QCPAxis::rangeChanged), poRectj-axis(QCPAxis::atBottom), QOverloadconst QCPRange::of(QCPAxis::setRange)); connect(poRecti-axis(QCPAxis::atLeft), QOverloadconst QCPRange::of(QCPAxis::rangeChanged), poRectj-axis(QCPAxis::atLeft), QOverloadconst QCPRange::of(QCPAxis::setRange)); } } } }5、初始化QCustomPlotvoid WdtCustomChart::initPlot() { m_plot new QCustomPlot(this); m_plot-plotLayout()-clear(); //// 允许用户用鼠标拖动轴范围以鼠标为中心滚轮缩放点击选择图形: m_plot-setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); }WdtCustomChart .h #pragma once #include qwidget.h #include qcustomplot.h #include QTimer #include datastruct.h #include WidgetEx.h #include DataDefine.h #include IntToString.h #include TreeDirectoryWidget.h class WdtCustomChart : public WidgetEx { Q_OBJECT public: WdtCustomChart(QWidget* parent); ~WdtCustomChart(); void init(); private: void initTreeData(QMapint, DevStationData* devMap); void initPlot(); void UpdateGraphPlot(QString id,bool check); //曲线号 void UpdateGraphPlotData(QString id, int key, double value); void UpdateGraphPlotData(QString id,int key); //多段y轴、共用x轴坐标系 //根据勾选的通道号创建坐标系 QCPAxisRect* CreateQCPAxisRect(QString channel); //删除坐标系 void RemoveQCPAxisRect(QString channel); //x轴y轴同步 void ConnectAllAxisx(bool on); //更新设置共用一个x轴 void UpdateSettingCommonXaXisx(); public slots: void SlotItemChange(QString id,bool check); void SlotDataTimeOut(); private: TreeDirectoryWidget* m_treeWidget nullptr; QCustomPlot* m_plot; QCPRange m_originXRange; QMapint, DevStationData* m_devMap; QMapQString, bool m_select_checkbox; QMapQString,int m_ploy_index_channel; //通道号 绑定 曲线号 //动态增加删除通道所对应的曲线图 QMapint, QCPAxisRect* m_channel_axises; //每一个通道相对应的纵坐标 QMapint, QCPGraph* m_channel_plots; //每一个通道所对应的曲线 QTimer* m_data_timer; //y轴动态变化值 int max 50; int min 0; };WdtCustomChart .cpp #include WdtCustomChart.h #include Language.h WdtCustomChart::WdtCustomChart(QWidget* parent):WidgetEx(parent) { } WdtCustomChart::~WdtCustomChart() { if (m_data_timer) { m_data_timer-stop(); delete m_data_timer; m_data_timer NULL; } } void WdtCustomChart::init() { if (m_treeWidget nullptr) { m_treeWidget new TreeDirectoryWidget(this); } initPlot(); initTreeData(m_devMap); QHBoxLayout* layout new QHBoxLayout; layout-addWidget(m_treeWidget,0); layout-addWidget(m_plot,1); setLayout(layout); connect(m_treeWidget, TreeDirectoryWidget::sig_itemCheckChange, this, WdtCustomChart::SlotItemChange); m_data_timer new QTimer; connect(m_data_timer, SIGNAL(timeout()), this, SLOT(SlotDataTimeOut())); m_data_timer-start(1000); } static const QColor colors[] { Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta, Qt::gray, Qt::darkRed, Qt::darkGreen, Qt::darkBlue, Qt::darkCyan, }; void WdtCustomChart::initPlot() { m_plot new QCustomPlot(this); m_plot-plotLayout()-clear(); //// 允许用户用鼠标拖动轴范围以鼠标为中心滚轮缩放点击选择图形: m_plot-setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); } void WdtCustomChart::initTreeData(QMapint, DevStationData* devMap) { for (int i 1; i 100; i) { DevStationData* data new DevStationData(); if (i 20) { >