feat:完成多坐标轴(数据类型)的动态配置,包括排列方式的动态设置
This commit is contained in:
parent
eaaafcbce0
commit
c120d6afc2
|
|
@ -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;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ private:
|
|||
QStandardItemModel* m_pModel_dataSource;
|
||||
QStandardItemModel* m_pModel_dataSelected;
|
||||
|
||||
QHash<RealTimeDataType, AxisCfgInfo> m_axisCfgInfo;
|
||||
QHash<RealTimeDataType, AxisCfgInfo> m_axisCfgMap;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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<RealTimeDataType, AxisCfgInfo> axisCfgInfo; //可能有多个轴(数据类别)
|
||||
QHash<RealTimeDataType, AxisCfgInfo> axisCfgMap; //可能有多个轴(数据类别)
|
||||
|
||||
configurationResults()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<const QCPRange &>(&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<QCPAxis::AxisType, int> 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<RealTimeDataType, AxisConfig> 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)
|
||||
|
|
|
|||
|
|
@ -34,12 +34,14 @@ public slots:
|
|||
|
||||
private:
|
||||
void initQCP();
|
||||
void arrangeAxes();
|
||||
|
||||
QCustomPlot* m_pCustomPlot;
|
||||
ChartStyle m_chartStyle;
|
||||
qint64 m_timeRange;
|
||||
QDateTime m_curDateTime;
|
||||
QVector<Axis> m_axes;
|
||||
AxisArrangementMode m_axisArrangementMode;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -713,7 +713,7 @@ background-color:transparent;
|
|||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>居右排列</string>
|
||||
<string>靠右排列</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
|
|
|
|||
Loading…
Reference in New Issue