From c120d6afc2cc157c87b4a4d4e953f110920e976d Mon Sep 17 00:00:00 2001 From: duanshengchao <519970194@qq.com> Date: Fri, 25 Jul 2025 17:42:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=AE=8C=E6=88=90=E5=A4=9A=E5=9D=90?= =?UTF-8?q?=E6=A0=87=E8=BD=B4=EF=BC=88=E6=95=B0=E6=8D=AE=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=EF=BC=89=E7=9A=84=E5=8A=A8=E6=80=81=E9=85=8D=E7=BD=AE=EF=BC=8C?= =?UTF-8?q?=E5=8C=85=E6=8B=AC=E6=8E=92=E5=88=97=E6=96=B9=E5=BC=8F=E7=9A=84?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dataPanel/dpBaseChart.h | 44 +++++++-- dataPanel/dpConfigurationDialog.cpp | 49 ++++++++-- dataPanel/dpConfigurationDialog.h | 2 +- dataPanel/dpGlobals.h | 5 +- dataPanel/dpLineChart.cpp | 143 ++++++++++++++++++++++++++-- dataPanel/dpLineChart.h | 2 + ui/dpConfigurationDialog.ui | 2 +- 7 files changed, 224 insertions(+), 23 deletions(-) diff --git a/dataPanel/dpBaseChart.h b/dataPanel/dpBaseChart.h index d5b5811..a622f31 100644 --- a/dataPanel/dpBaseChart.h +++ b/dataPanel/dpBaseChart.h @@ -22,6 +22,8 @@ protected: { QColor bgColor; //背景颜色 QColor axisColor; //坐标轴颜色 + QColor labelColor; //坐标轴标签颜色 + QFont labelFont; //坐标轴标签字体 QColor tickColor; //刻度颜色 QColor tickLabelColor; //刻度label颜色 QFont tickLabelFont; //刻度label字体 @@ -38,12 +40,36 @@ protected: { AxisConfig _cfg; - QCPAxis* qAxis = nullptr; + QCPAxis* qAxis; + bool bIsDefaultAxis; //一个plot包含两个默认坐标轴axis和axis2 + ChartStyle style; - Axis(const AxisConfig& cfg, QCPAxisRect* rect) + Axis() { - applyConfig(cfg); - qAxis = new QCPAxis(rect, QCPAxis::atRight); + qAxis = nullptr; + bIsDefaultAxis = false; + } + + void setQCPAxis( QCPAxis* axis, bool isDefualtAxis) + { + qAxis = axis; + bIsDefaultAxis = isDefualtAxis; + if(qAxis) + { + qAxis->setLabel(_cfg.name); + qAxis->setSubTicks(false); + //颜色 + qAxis->setBasePen(style.axisColor); + //label + qAxis->setLabelColor(style.labelColor); + qAxis->setLabelFont(style.labelFont); + //刻度颜色 + qAxis->setTickPen(QPen(style.tickColor)); + //刻度Label颜色 + qAxis->setTickLabelColor(style.tickLabelColor); + qAxis->setTickLabelFont(style.tickLabelFont); + qAxis->setTickLabelColor(style.tickLabelColor); + } } void applyConfig(const AxisConfig& cfg) @@ -53,13 +79,19 @@ protected: _cfg.dataType = cfg.dataType; } + void setStyle(const ChartStyle chartStyle) + { + style = chartStyle; + } + ~Axis() { - if(qAxis) + //执行plot->axisRect()->removeAxis(axis)时,axis会delete掉 + /*if(qAxis && !bIsDefaultAxis) //默认坐标轴由所属plot管理 { delete qAxis; qAxis = nullptr; - } + }*/ } }; }; diff --git a/dataPanel/dpConfigurationDialog.cpp b/dataPanel/dpConfigurationDialog.cpp index 3c6db7d..3240341 100644 --- a/dataPanel/dpConfigurationDialog.cpp +++ b/dataPanel/dpConfigurationDialog.cpp @@ -79,18 +79,22 @@ void dpConfigurationDialog::initialize() item->setEditable(false); //不可编辑 m_pModel_typeSource->appendRow(item); }*/ - QStandardItem* item = new QStandardItem(QString::fromStdWString(L"电压")); + QStandardItem* item = new QStandardItem("电压"); item->setData(RealTimeDataType::voltage, Qt::UserRole + itemRole_dataType); item->setEditable(false); //不可编辑 m_pModel_typeSource->appendRow(item); - item = new QStandardItem(QString::fromStdWString(L"电流")); + item = new QStandardItem("电流"); item->setData(RealTimeDataType::current, Qt::UserRole + itemRole_dataType); item->setEditable(false); //不可编辑 m_pModel_typeSource->appendRow(item); - item = new QStandardItem(QString::fromStdWString(L"功率")); + item = new QStandardItem("功率"); item->setData(RealTimeDataType::power, Qt::UserRole + itemRole_dataType); item->setEditable(false); //不可编辑 m_pModel_typeSource->appendRow(item); + item = new QStandardItem("温度"); + item->setData(RealTimeDataType::temperature, Qt::UserRole + itemRole_dataType); + item->setEditable(false); //不可编辑 + m_pModel_typeSource->appendRow(item); //typeSelectedList ui->typeSelectedList->setSelectionBehavior(QAbstractItemView::SelectRows); m_pModel_typeSelected = new QStandardItemModel(this); @@ -141,6 +145,8 @@ void dpConfigurationDialog::copyModelData(QStandardItemModel* sourceModel, QStan if(item) { QStandardItem* newItem = new QStandardItem(item->text()); + RealTimeDataType dataType = (RealTimeDataType)item->data(Qt::UserRole + itemRole_dataType).toInt(); + newItem->setData(dataType, Qt::UserRole + itemRole_dataType); itemList.push_back(newItem); } } @@ -187,6 +193,14 @@ void dpConfigurationDialog::createDataSourceList() powerItem->setData(2, Qt::UserRole + itemRole_pointID); powerItem->setData(RealTimeDataType::power, Qt::UserRole + itemRole_dataType); componentItem->appendRow(powerItem); + QStandardItem* tempItem = new QStandardItem("温度"); + tempItem->setEditable(false); + tempItem->setData("point", Qt::UserRole + itemRole_tag); + tempItem->setData(i, Qt::UserRole + itemRole_stationID); + tempItem->setData(0, Qt::UserRole + itemRole_componentID); + tempItem->setData(2, Qt::UserRole + itemRole_pointID); + tempItem->setData(RealTimeDataType::temperature, Qt::UserRole + itemRole_dataType); + componentItem->appendRow(tempItem); } ui->dataSourceList->expandAll(); @@ -212,6 +226,9 @@ void dpConfigurationDialog::removeDataSelected(int deleteRow) void dpConfigurationDialog::setPanel(DataPanel* pPanel) { + if(!pPanel) + return; + m_pDataPanel = pPanel; copyModelData(pPanel->m_cofigurationResults.m_pModel_dataType, m_pModel_typeSelected); copyModelData(pPanel->m_cofigurationResults.m_pModel_dataSource, m_pModel_dataSelected); @@ -231,7 +248,15 @@ void dpConfigurationDialog::setPanel(DataPanel* pPanel) ui->specialSettings->setCurrentIndex(0); ui->specialSettings->setVisible(true); ui->axisObject->clear(); - m_axisCfgInfo.clear(); + m_axisCfgMap.clear(); + + for(int i = 0; i< m_pModel_typeSelected->rowCount(); i++) + { + RealTimeDataType dataType = (RealTimeDataType)m_pModel_typeSelected->item(i, 0)->data(Qt::UserRole + itemRole_dataType).toInt(); + QString itemText = m_pModel_typeSelected->item(i, 0)->text(); + ui->axisObject->addItem(itemText, dataType); + } + m_axisCfgMap = pPanel->m_cofigurationResults.axisCfgMap; break; } default: @@ -300,6 +325,7 @@ void dpConfigurationDialog::onBtnClicked_confirm() m_pDataPanel->m_cofigurationResults.dataServiceIP = ui->serviceIP->text(); m_pDataPanel->m_cofigurationResults.dataServicePort = ui->servicePort->text().toInt(); m_pDataPanel->m_cofigurationResults.arrangement = (AxisArrangementMode)ui->axisArrangement->currentIndex(); + m_pDataPanel->m_cofigurationResults.axisCfgMap = m_axisCfgMap; m_pDataPanel->configurationComplete(); } } @@ -326,11 +352,18 @@ void dpConfigurationDialog::onItemClicked_typeSource(const QModelIndex& index) } } + if(!m_pDataPanel) + { + ui->errorTip->setVisible(true); + ui->errorTip->setToolTip(QString("当前面板对象为nullptr")); + return; + } + if(!bIsHad && m_pModel_typeSelected) { int nMaximumType = m_pModel_typeSelected->rowCount(); if(m_pDataPanel && (m_pDataPanel->getType() == lineChart || m_pDataPanel->getType() == curveChart)) - nMaximumType = 2; + nMaximumType = 4; if(m_pModel_typeSelected->rowCount() >= nMaximumType) { @@ -358,7 +391,9 @@ void dpConfigurationDialog::onItemClicked_typeSource(const QModelIndex& index) case curveChart: case barChart: { - m_axisCfgInfo.insert(dataType, AxisCfgInfo()); + AxisCfgInfo cfg; + cfg.name = item->text(); + m_axisCfgMap.insert(dataType, cfg); ui->axisObject->addItem(item->text(), dataType); break; } @@ -406,7 +441,7 @@ void dpConfigurationDialog::onBtnClicked_remove_type() case curveChart: case barChart: { - m_axisCfgInfo.remove(itemDataType); + m_axisCfgMap.remove(itemDataType); int index = ui->axisObject->findData(itemDataType); if(index != -1) ui->axisObject->removeItem(index); diff --git a/dataPanel/dpConfigurationDialog.h b/dataPanel/dpConfigurationDialog.h index 0bb1a2a..03a6096 100644 --- a/dataPanel/dpConfigurationDialog.h +++ b/dataPanel/dpConfigurationDialog.h @@ -59,7 +59,7 @@ private: QStandardItemModel* m_pModel_dataSource; QStandardItemModel* m_pModel_dataSelected; - QHash m_axisCfgInfo; + QHash m_axisCfgMap; }; diff --git a/dataPanel/dpGlobals.h b/dataPanel/dpGlobals.h index a035681..133d87e 100644 --- a/dataPanel/dpGlobals.h +++ b/dataPanel/dpGlobals.h @@ -18,7 +18,8 @@ enum RealTimeDataType { power = 0, //功率 voltage, //电压 - current //电流 + current, //电流 + temperature //温度 }; enum AxisArrangementMode //坐标轴排列方式 @@ -40,7 +41,7 @@ struct configurationResults QString dataServiceIP; int dataServicePort; AxisArrangementMode arrangement; - QHash axisCfgInfo; //可能有多个轴(数据类别) + QHash axisCfgMap; //可能有多个轴(数据类别) configurationResults() { diff --git a/dataPanel/dpLineChart.cpp b/dataPanel/dpLineChart.cpp index c64a3fa..db8a3d6 100644 --- a/dataPanel/dpLineChart.cpp +++ b/dataPanel/dpLineChart.cpp @@ -1,5 +1,6 @@ #include "dpLineChart.h" +//#define useDefaultAxis_Y //默认轴不可删除、不可左右移动,所以做动态管理尤其是动态排列时要考虑的比较复杂,可以采用不使用的策略,全部以自定义轴替代,默认轴(yAxis)只在初始化和没有实际数据轴(自定义)时显示用来做外观展示 dpLineChart::dpLineChart(QWidget* parent) :dpBaseChart(parent) { @@ -9,6 +10,7 @@ dpLineChart::dpLineChart(QWidget* parent) initQCP(); m_timeRange = 60 * 1000; + m_axisArrangementMode = AlternateSides; QBoxLayout* mainLayout = new QBoxLayout(QBoxLayout::LeftToRight); mainLayout->setContentsMargins(0, 1, 0, 0); @@ -24,6 +26,8 @@ void dpLineChart::initQCP() { m_chartStyle.bgColor = Qt::transparent; m_chartStyle.axisColor = QColor(87, 100, 120); + m_chartStyle.labelColor = QColor(250, 250, 250); + m_chartStyle.labelFont = QFont("黑体", 12); m_chartStyle.tickColor = QColor(87, 100, 120); m_chartStyle.tickLabelColor = QColor(250, 250, 250); m_chartStyle.tickLabelFont = QFont("黑体", 12); @@ -38,9 +42,10 @@ void dpLineChart::initQCP() m_pCustomPlot->xAxis2->setTicks(false); m_pCustomPlot->xAxis2->setSubTicks(false); m_pCustomPlot->yAxis->setSubTicks(false); + //m_pCustomPlot->yAxis->setVisible(false); //m_pCustomPlot->yAxis2->setTicks(false); m_pCustomPlot->yAxis2->setSubTicks(false); - m_pCustomPlot->yAxis2->setVisible(true); + m_pCustomPlot->yAxis2->setVisible(false); connect(m_pCustomPlot->xAxis, qOverload(&QCPAxis::rangeChanged), //rangeChanged有两个版本,qOverload可以指定版本 this, &dpLineChart::onSignal_rangeChanged_xAxis); //背景颜色 @@ -76,6 +81,43 @@ void dpLineChart::initQCP() //qDebug() << m_pCustomPlot->xAxis->range(); } +void dpLineChart::arrangeAxes() +{ + QMap axisTypeCounter; + for(int i = 0; i < m_axes.size(); i++) + { + Axis& axis = m_axes[i]; + + QCPAxis::AxisType position = axis.qAxis->axisType(); + if(m_axisArrangementMode == AlternateSides) + position = (i % 2 == 0) ? QCPAxis::atLeft : QCPAxis::atRight; + else if(m_axisArrangementMode == AllRight) + { + if(i == 0) + position = QCPAxis::atLeft; + else + position = QCPAxis::atRight; + } + + //更新位置,因为QCPAxis没有更新位置的结构,只能采用从plot中移除再添加的方式 + if(axis.qAxis->axisType() != position) + { + bool bRemoved = m_pCustomPlot->axisRect()->removeAxis(axis.qAxis); + if(bRemoved) //removeAxis执行成功,被删除的axis会被delete + { + QCPAxis* qcpAxis = m_pCustomPlot->axisRect()->addAxis(position); + axis.setQCPAxis(qcpAxis, false); + } + + } + + //计算偏移量 + int offset = axisTypeCounter.value(position, 0) * 30; + axis.qAxis->setOffset(offset); + axisTypeCounter[position] = axisTypeCounter.value(position, 0) + 1; + } +} + void dpLineChart::setTimeRange(TimeUnit unit) { switch(unit) @@ -159,14 +201,20 @@ void dpLineChart::synchronizeConfigData(const configurationResults& cfg) //将最新配置信息中的坐标轴相关数据存储在QHash中,有助于更好的判断当前坐标轴是否需要发生同步更新 QHash axisCfgMap; - for(int i = 0; i< cfg.m_pModel_dataType->rowCount(); i++) + /*for(int i = 0; i< cfg.m_pModel_dataType->rowCount(); i++) { AxisConfig axisConfig; - //axisConfig.name = cfg.axisInfo.name; - //axisConfig.unit = cfg.axisInfo.unit; RealTimeDataType dataType = (RealTimeDataType)cfg.m_pModel_dataType->item(i, 0)->data(Qt::UserRole + itemRole_dataType).toInt(); axisConfig.dataType = dataType; axisCfgMap.insert(dataType, axisConfig); + }*/ + for(auto it = cfg.axisCfgMap.begin(); it != cfg.axisCfgMap.end(); ++it) + { + AxisConfig axisConfig; + axisConfig.dataType = it.key(); + axisConfig.name = it.value().name; + axisConfig.unit = it.value().unit; + axisCfgMap.insert(it.key(), axisConfig); } //QHash::insert()的第二个参数接收的是副本(引起拷贝),所以采用指针可以减少拷贝从而提升效率 @@ -179,17 +227,100 @@ void dpLineChart::synchronizeConfigData(const configurationResults& cfg) //删除轴 for(int i = 0; i < m_axes.size();) { +#ifdef useDefaultAxis_Y + Axis& axis = m_axes[i]; + if(!axisCfgMap.contains(axis._cfg.dataType)) + { + if(axis.qAxis != m_pCustomPlot->yAxis && axis.qAxis != m_pCustomPlot->yAxis2) + m_pCustomPlot->axisRect()->removeAxis(axis.qAxis); + else + axis.qAxis->setVisible(false); + + m_axes.remove(i); + } + else + i++; +#else Axis& axis = m_axes[i]; if(!axisCfgMap.contains(axis._cfg.dataType)) { m_pCustomPlot->axisRect()->removeAxis(axis.qAxis); - m_axes.remove(i); //QVector::remove()会调用存储对象的析构函数 + m_axes.remove(i); } else i++; +#endif + } + if(m_axes.isEmpty()) //若所有轴(数据类型)全部清楚,将默认左轴xAxis显示出来 + m_pCustomPlot->xAxis->setVisible(true); + + //处理应用配置(新增或更新) + for(int i = 0; i < cfg.m_pModel_dataType->rowCount(); i++) //能保证和选取顺序一致 + //for(auto it = axisCfgMap.begin(); it != axisCfgMap.end(); ++it) + { + RealTimeDataType dataType = (RealTimeDataType)cfg.m_pModel_dataType->item(i, 0)->data(Qt::UserRole + itemRole_dataType).toInt(); + //RealTimeDataType dataType = it.key(); + if(axesMap.contains(dataType)) //更新配置 + { + + } + else //新增轴 + { +#ifdef useDefaultAxis_Y + AxisConfig cfg = axisCfgMap.value(dataType); + Axis axis; + if(m_axes.isEmpty()) //使用默认轴yAxis + { + axis.setQCPAxis(m_pCustomPlot->yAxis, true); + } + else if(m_axes.count() == 1 && m_axes.at(0).qAxis == m_pCustomPlot->yAxis) //默认轴yAxis被使用,使用yAxis2 + { + axis.setQCPAxis(m_pCustomPlot->yAxis2, true); + m_pCustomPlot->yAxis2->setVisible(false); + } + else + { + QCPAxis* pAxis = new QCPAxis(m_pCustomPlot->axisRect(), QCPAxis::atRight); + axis.setQCPAxis(pAxis, false); + axis.setStyle(m_chartStyle); + } + axis.applyConfig(cfg); + m_axes.append(axis); +#else + AxisConfig axisCfg = axisCfgMap.value(dataType); + Axis axis; + axis.applyConfig(axisCfg); + axis.setStyle(m_chartStyle); + if(m_axes.isEmpty()) + { + //隐藏默认左轴 + m_pCustomPlot->yAxis->setVisible(false); + //创建自定义轴代替 + //QCPAxis* pAxis = new QCPAxis(m_pCustomPlot->axisRect(), QCPAxis::atLeft); + QCPAxis* pAxis = m_pCustomPlot->axisRect()->addAxis(QCPAxis::atLeft); + if(!pAxis) + continue; + //qDebug() << "add axis on:" << QCPAxis::atLeft << ", name: " << axisCfg.name; + axis.setQCPAxis(pAxis, false); + + } + else + { + //默认放在右边 + //QCPAxis* pAxis = new QCPAxis(m_pCustomPlot->axisRect(), QCPAxis::atRight); + QCPAxis* pAxis = m_pCustomPlot->axisRect()->addAxis(QCPAxis::atRight); + if(!pAxis) + continue; + axis.setQCPAxis(pAxis, false); + } + m_axes.append(axis); +#endif + } } - + //重新排列坐标轴 + m_axisArrangementMode = cfg.arrangement; + arrangeAxes(); } void dpLineChart::onSignal_rangeChanged_xAxis(const QCPRange& range) diff --git a/dataPanel/dpLineChart.h b/dataPanel/dpLineChart.h index 4f7fffc..9477c58 100644 --- a/dataPanel/dpLineChart.h +++ b/dataPanel/dpLineChart.h @@ -34,12 +34,14 @@ public slots: private: void initQCP(); + void arrangeAxes(); QCustomPlot* m_pCustomPlot; ChartStyle m_chartStyle; qint64 m_timeRange; QDateTime m_curDateTime; QVector m_axes; + AxisArrangementMode m_axisArrangementMode; }; #endif diff --git a/ui/dpConfigurationDialog.ui b/ui/dpConfigurationDialog.ui index b6690f9..268906e 100644 --- a/ui/dpConfigurationDialog.ui +++ b/ui/dpConfigurationDialog.ui @@ -713,7 +713,7 @@ background-color:transparent; - 居右排列 + 靠右排列