feat:完成柱状图的基本绘制

This commit is contained in:
duanshengchao 2025-09-01 19:57:02 +08:00
parent d4c24d364f
commit 605b8dd190
9 changed files with 289 additions and 48 deletions

View File

@ -7,8 +7,8 @@ dpBarsChart::dpBarsChart(QWidget* parent)
setAttribute(Qt::WA_TranslucentBackground,true);
m_pCustomPlot = new QCustomPlot(this);
initQCP();
m_barsGroup = new QCPBarsGroup(m_pCustomPlot);
initQCP();
QBoxLayout* mainLayout = new QBoxLayout(QBoxLayout::LeftToRight);
mainLayout->setContentsMargins(0, 1, 0, 0);
@ -37,9 +37,9 @@ void dpBarsChart::initQCP()
/*m_pCustomPlot->axisRect()->setRangeDrag(Qt::Horizontal); //只允许x轴方向的拖拽
double zoomFactor = m_pCustomPlot->axisRect()->rangeZoomFactor(Qt::Horizontal);
m_pCustomPlot->axisRect()->setRangeZoomFactor(zoomFactor, 1); //只做x轴的缩放*/
m_pCustomPlot->xAxis->setTicks(false);
//m_pCustomPlot->xAxis->setTicks(false);
m_pCustomPlot->xAxis->setSubTicks(false);
m_pCustomPlot->yAxis->setTicks(false);
//m_pCustomPlot->yAxis->setTicks(false);
m_pCustomPlot->yAxis->setSubTicks(false);
//m_pCustomPlot->yAxis->setVisible(false);
//m_pCustomPlot->yAxis2->setTicks(false);
@ -92,7 +92,146 @@ void dpBarsChart::viewHistoricalData(const QDateTime& dateTime)
{}
void dpBarsChart::synchronizeConfigData(const configurationResults& cfg)
{}
{
//先清除现有图形(直方图不像曲线一样有连续的过程展现,所以不采用动态更新,每次都清除、重新创建)
m_pCustomPlot->clearPlottables();
m_bars.clear();
bool groupByType = false;
//设定朝向
QCPAxis* keyAxis = nullptr;
QCPAxis* valueAxis = nullptr;
if(cfg.barOrientataion == Vertical)
{
keyAxis = m_pCustomPlot->xAxis;
valueAxis = m_pCustomPlot->yAxis;
}
else
{
keyAxis = m_pCustomPlot->yAxis;
valueAxis = m_pCustomPlot->xAxis;
}
if(!keyAxis && !valueAxis)
return;
QVector<double> ticks;
int tick = 0;
QVector<QString> tickLabels;
QHash<RealTimeDataType, QSet<QString>> groupedBars; //按数据类型对bar进行分组以实现可以按组放置以及设置颜色等操作
for(int i = 0; i < cfg.m_pModel_dataSource->rowCount(); i++)
{
QString itemText = cfg.m_pModel_dataSource->item(i, 0)->text();
QString stationID = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_stationID).toString();
QString compoentID = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_componentID).toString();
QString pointID = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_pointID).toString();
QString dataID = stationID + "-" + compoentID + "-" + pointID;
QVariant colorData = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::DecorationRole);
RealTimeDataType dataType = (RealTimeDataType)cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_dataType).toInt();
/*QCPBarsGroup* barsGroup = nullptr;
if(!m_barsGroups.contains(dataType))
{
barsGroup = new QCPBarsGroup(m_pCustomPlot);
m_barsGroups.insert(dataType, barsGroup);
}
else
{
barsGroup = m_barsGroups.value(dataType);
}
if(!barsGroup)
continue;*/
Bars bars;
bars.name = itemText;
bars.dataID = dataID;
bars.dataType = dataType;
bars.color = colorData.value<QColor>();
QCPBars* qBars = new QCPBars(keyAxis, valueAxis);
qBars->setName(bars.name);
qBars->setPen(bars.color); //边框颜色
qBars->setBrush(bars.color); //填充颜色
bars.qBars = qBars;
if(groupByType)
groupedBars[dataType].insert(dataID);
else
{
ticks << ++tick;
tickLabels << itemText;
bars.keys << tick;
}
m_bars.insert(dataID, bars);
}
if(groupByType)
{
for(auto it = groupedBars.begin(); it != groupedBars.end(); ++it)
{
ticks.push_back(++tick);
switch(it.key())
{
case power:
tickLabels.push_back("功率");
break;
case voltage:
tickLabels.push_back("电压");
break;
case current:
tickLabels.push_back("电流");
break;
case temperature:
tickLabels.push_back("温度");
break;
default:
tickLabels.push_back("未定义");
break;
}
for(auto bars_it = it.value().begin(); bars_it != it.value().end(); ++bars_it)
{
QString dataID = *bars_it;
if(m_bars.contains(dataID))
m_bars[dataID].keys.push_back(tick);
}
}
}
QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
textTicker->addTicks(ticks, tickLabels);
keyAxis->setTicker(textTicker);
keyAxis->setRange(1, ticks.count());
if(groupByType)
keyAxis->setTickLabels(true);
else
keyAxis->setTickLabels(false);
valueAxis->setTickLabels(true);
valueAxis->setRange(0, 11);
for(auto it = m_bars.begin(); it != m_bars.end(); ++it)
{
if(it.value().qBars.isNull())
continue;
//随机模拟值
QVector<double> values;
double randomVaule = 1 + QRandomGenerator::global()->generateDouble() * (8 - 1);
values << randomVaule;
it.value().qBars->setData(it.value().keys, values);
if(groupByType)
it.value().qBars->setBarsGroup(m_barsGroup);
}
//Legend
m_pCustomPlot->legend->setVisible(cfg.showLegend);
m_pCustomPlot->replot();
}
void dpBarsChart::onSignal_dataUpdated(const QString& dataKey, const QVariant& data, const QDateTime& timestamp)
{}

View File

@ -33,11 +33,29 @@ public slots:
void onSignal_dataUpdated(const QString& dataKey, const QVariant& data, const QDateTime& timestamp);
private:
struct Bars
{
QColor color;
QString name;
QString dataID;
RealTimeDataType dataType;
QVector<double> keys;
QPointer<QCPBars> qBars;
Bars()
{
name = "";
dataID = "";
}
};
void initQCP();
QCustomPlot* m_pCustomPlot;
ChartStyle m_chartStyle;
QCPBarsGroup* m_barsGroup;
QHash<QString, Bars> m_bars;
//QHash<RealTimeDataType, QCPBarsGroup*> m_barsGroups;
};
#endif

View File

@ -115,25 +115,6 @@ protected:
};
struct Graph
{
QColor color;
RealTimeDataType dataType;
//QCPGraph* qGraph;
QPointer<QCPGraph> qGraph;
QString dataID;
QString synchronizeTagging; //同步配置数据时的标记new、update两种没有的就是要被删除
QString name; //用户legend图例展示用
Graph()
{
dataID = "";
//qGraph = nullptr;
synchronizeTagging = "noTagging";
name = "";
}
};
};
#endif

View File

@ -257,8 +257,8 @@ void dpConfigurationDialog::setPanel(DataPanel* pPanel)
{
case lineChart:
{
ui->specialSettings->setCurrentIndex(0);
ui->specialSettings->setVisible(true);
ui->specialSettings->setCurrentIndex(0);
ui->axisObject->clear();
m_axisCfgMap.clear();
ui->axisName->setText("");
@ -289,6 +289,11 @@ void dpConfigurationDialog::setPanel(DataPanel* pPanel)
break;
}
case barChart:
{
ui->specialSettings->setVisible(true);
ui->specialSettings->setCurrentIndex(1);
break;
}
default:
ui->specialSettings->setVisible(false);
break;
@ -357,14 +362,26 @@ 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.showLegend = ui->radioBtn_showLegend->isChecked();
m_pDataPanel->m_cofigurationResults.arrangement = (AxisArrangementMode)ui->axisArrangement->currentIndex();
RealTimeDataType itemDataType = (RealTimeDataType)ui->axisObject->currentData().toInt();
if(m_axisCfgMap.contains(itemDataType))
m_pDataPanel->m_cofigurationResults.axisArrangement = (AxisArrangementMode)ui->axisArrangement->currentIndex();
DataPanelType panelType = m_pDataPanel->getType();
switch (panelType)
{
if(!ui->axisName->text().isEmpty())
m_axisCfgMap[itemDataType].name = ui->axisName->text();
m_axisCfgMap[itemDataType].unit = ui->axisUnit->text();
case lineChart:
{
RealTimeDataType itemDataType = (RealTimeDataType)ui->axisObject->currentData().toInt();
if(m_axisCfgMap.contains(itemDataType))
{
if(!ui->axisName->text().isEmpty())
m_axisCfgMap[itemDataType].name = ui->axisName->text();
m_axisCfgMap[itemDataType].unit = ui->axisUnit->text();
}
break;
}
default:
break;
}
m_pDataPanel->m_cofigurationResults.axisCfgMap = m_axisCfgMap;
m_pDataPanel->configurationComplete();
}
@ -401,8 +418,8 @@ void dpConfigurationDialog::onItemClicked_typeSource(const QModelIndex& index)
if(!bIsHad && m_pModel_typeSelected)
{
int nMaximumType = m_pModel_typeSelected->rowCount();
if(m_pDataPanel && (m_pDataPanel->getType() == lineChart || m_pDataPanel->getType() == curveChart))
int nMaximumType = m_pModel_typeSource->rowCount();
if(m_pDataPanel && (m_pDataPanel->getType() == lineChart || m_pDataPanel->getType() == barChart))
nMaximumType = 4;
if(m_pModel_typeSelected->rowCount() >= nMaximumType)
@ -428,8 +445,6 @@ void dpConfigurationDialog::onItemClicked_typeSource(const QModelIndex& index)
switch (panelType)
{
case lineChart:
case curveChart:
case barChart:
{
AxisCfgInfo cfg;
cfg.name = item->text();
@ -442,6 +457,10 @@ void dpConfigurationDialog::onItemClicked_typeSource(const QModelIndex& index)
connect(ui->axisObject, &QComboBox::currentIndexChanged, this, &dpConfigurationDialog::onComboBoxIndexChanged_axis);
break;
}
case barChart:
{
break;
}
default:
break;
}
@ -483,8 +502,6 @@ void dpConfigurationDialog::onBtnClicked_remove_type()
switch (panelType)
{
case lineChart:
case curveChart:
case barChart:
{
m_axisCfgMap.remove(itemDataType);
int index = ui->axisObject->findData(itemDataType);
@ -500,6 +517,10 @@ void dpConfigurationDialog::onBtnClicked_remove_type()
}
break;
}
case barChart:
{
break;
}
default:
break;
}

View File

@ -62,6 +62,7 @@ private:
QStandardItemModel* m_pModel_dataSource;
QStandardItemModel* m_pModel_dataSelected;
//特定配置项
QHash<RealTimeDataType, AxisCfgInfo> m_axisCfgMap;
int m_curAxisComboBoxIndex;
};

View File

@ -3,8 +3,8 @@
enum DataPanelType
{
lineChart = 0, //线图
curveChart, //曲线图
lineChart = 0, //线图
//curveChart, //曲线图
barChart, //柱状图
dotChart, //点图
pieChart, //饼图
@ -28,6 +28,12 @@ enum AxisArrangementMode //坐标轴排列方式
AllRight //右侧排列
};
enum BarOrientation //直方图方向
{
Horizontal = 0,
Vertical
};
#include <QStandardItemModel>
struct AxisCfgInfo
{
@ -41,7 +47,8 @@ struct configurationResults
QString dataServiceIP;
int dataServicePort;
bool showLegend;
AxisArrangementMode arrangement;
AxisArrangementMode axisArrangement;
BarOrientation barOrientataion;
QHash<RealTimeDataType, AxisCfgInfo> axisCfgMap; //可能有多个轴(数据类别)
configurationResults()
@ -53,7 +60,8 @@ struct configurationResults
dataServicePort = 1987;
showLegend = false;
arrangement = AlternateSides;
axisArrangement = AlternateSides;
barOrientataion = Vertical;
}
void setModelParent(QObject* parent) //为QStandardItemModel对象构造对象树从而利用QT的资源自动管理

View File

@ -421,7 +421,7 @@ void dpLineChart::synchronizeConfigData(const configurationResults& cfg)
}
//重新排列坐标轴
m_axisArrangementMode = cfg.arrangement;
m_axisArrangementMode = cfg.axisArrangement;
arrangeAxes();
//2.曲线-数据源决定

View File

@ -41,6 +41,26 @@ private:
ReassignToOthrer //重新分配到其它坐标轴
};
struct Graph
{
QColor color;
RealTimeDataType dataType;
//QCPGraph* qGraph;
QPointer<QCPGraph> qGraph;
QString dataID;
QString synchronizeTagging; //同步配置数据时的标记new、update两种没有的就是要被删除
QString name; //用户legend图例展示用
Graph()
{
dataID = "";
//qGraph = nullptr;
synchronizeTagging = "noTagging";
name = "";
}
};
void initQCP();
void arrangeAxes();
void reLayoutLegend();

View File

@ -618,17 +618,17 @@ background-color: rgb(24, 32, 38);
<property name="geometry">
<rect>
<x>0</x>
<y>150</y>
<y>155</y>
<width>521</width>
<height>181</height>
<height>121</height>
</rect>
</property>
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="lineChart">
<widget class="QWidget" name="axisCfg">
<property name="styleSheet">
<string notr="true">QWidget #coordinate
<string notr="true">QWidget #axisCfg
{
background-color:transparent;
}</string>
@ -751,13 +751,66 @@ background-color:transparent;
</property>
</widget>
</widget>
<widget class="QWidget" name="page_2"/>
<widget class="QWidget" name="barsCfg">
<property name="styleSheet">
<string notr="true">QWidget #barsCfg
{
background-color:transparent;
}</string>
</property>
<widget class="QComboBox" name="barOrientation">
<property name="geometry">
<rect>
<x>80</x>
<y>10</y>
<width>91</width>
<height>22</height>
</rect>
</property>
<item>
<property name="text">
<string>水平方向</string>
</property>
</item>
<item>
<property name="text">
<string>垂直方向</string>
</property>
</item>
</widget>
<widget class="QLabel" name="label_barOrientation">
<property name="geometry">
<rect>
<x>0</x>
<y>10</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>图形朝向:</string>
</property>
</widget>
<widget class="QRadioButton" name="groupByType">
<property name="geometry">
<rect>
<x>0</x>
<y>40</y>
<width>161</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>按类型分组</string>
</property>
</widget>
</widget>
</widget>
<widget class="QRadioButton" name="radioBtn_showLegend">
<property name="geometry">
<rect>
<x>0</x>
<y>105</y>
<y>110</y>
<width>121</width>
<height>31</height>
</rect>