2025-03-10 09:35:07 +00:00
|
|
|
|
#include <QHBoxLayout>
|
|
|
|
|
|
#include <QRandomGenerator>
|
2025-03-25 08:45:16 +00:00
|
|
|
|
#include <cmath>
|
|
|
|
|
|
#include <limits>
|
|
|
|
|
|
#include <qcustomplot.h>
|
2025-03-10 09:35:07 +00:00
|
|
|
|
|
|
|
|
|
|
#include "centralwidget.h"
|
2025-03-17 13:16:16 +00:00
|
|
|
|
#include "filemanager.h"
|
2025-03-26 09:30:02 +00:00
|
|
|
|
#include "peakpoint.h"
|
2025-03-27 09:31:19 +00:00
|
|
|
|
#include "logger.h"
|
2025-03-10 09:35:07 +00:00
|
|
|
|
|
2025-03-12 09:29:52 +00:00
|
|
|
|
CentralWidget::CentralWidget(QWidget *parent)
|
|
|
|
|
|
: QWidget(parent),
|
2025-03-24 09:30:42 +00:00
|
|
|
|
_customPlot(new QCustomPlot(this))
|
2025-03-21 09:28:36 +00:00
|
|
|
|
,_nanlysisMode(AnalysisMode::None)
|
2025-03-10 09:35:07 +00:00
|
|
|
|
{
|
2025-03-21 09:28:36 +00:00
|
|
|
|
setMouseTracking(true);
|
|
|
|
|
|
|
2025-03-10 09:35:07 +00:00
|
|
|
|
setStyleSheet("background-color: lightgray;");
|
|
|
|
|
|
resize(888, 666);
|
|
|
|
|
|
|
2025-03-12 09:29:52 +00:00
|
|
|
|
QHBoxLayout *layout = new QHBoxLayout();
|
2025-03-21 09:28:36 +00:00
|
|
|
|
layout->setMargin(0);
|
2025-03-10 09:35:07 +00:00
|
|
|
|
layout->addWidget(_customPlot);
|
|
|
|
|
|
this->setLayout(layout);
|
|
|
|
|
|
|
2025-03-20 09:28:22 +00:00
|
|
|
|
// 创建两条竖线
|
|
|
|
|
|
_line1 = new QCPItemStraightLine(_customPlot);
|
|
|
|
|
|
_line1->point1->setCoords(20, _customPlot->yAxis->range().lower);
|
|
|
|
|
|
_line1->point2->setCoords(20, _customPlot->yAxis->range().upper);
|
|
|
|
|
|
_line1->setPen(QPen(Qt::red));
|
|
|
|
|
|
_line1->setSelectable(true);
|
|
|
|
|
|
|
|
|
|
|
|
_line2 = new QCPItemStraightLine(_customPlot);
|
|
|
|
|
|
_line2->point1->setCoords(40, _customPlot->yAxis->range().lower);
|
|
|
|
|
|
_line2->point2->setCoords(40, _customPlot->yAxis->range().upper);
|
|
|
|
|
|
_line2->setPen(QPen(Qt::red));
|
|
|
|
|
|
_line2->setSelectable(true);
|
|
|
|
|
|
|
|
|
|
|
|
// 安装事件过滤器
|
2025-03-21 09:28:36 +00:00
|
|
|
|
_graph = _customPlot->addGraph(0);
|
|
|
|
|
|
_eventHandler = new DragLineHandler(_customPlot, _line1, _line2, _graph, nullptr);
|
2025-03-20 09:28:22 +00:00
|
|
|
|
_customPlot->installEventFilter(_eventHandler);
|
|
|
|
|
|
|
2025-03-21 09:28:36 +00:00
|
|
|
|
connect(_eventHandler,&DragLineHandler::sigSendLineXCoord,
|
|
|
|
|
|
this,&CentralWidget::sigSendLineXCoord);
|
|
|
|
|
|
|
|
|
|
|
|
setEventHandlerEnable(false);
|
|
|
|
|
|
//
|
2025-03-10 09:35:07 +00:00
|
|
|
|
#if 0
|
|
|
|
|
|
// init data
|
|
|
|
|
|
QVector<double> x(101), y(101);
|
|
|
|
|
|
for (int i = 0; i < 101; i++) {
|
|
|
|
|
|
x[i] = i / 50.0 - 1;//设置x的范围为-1~1
|
|
|
|
|
|
y[i] = x[i] * x[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_customPlot->graph(0)->setData(x, y);
|
|
|
|
|
|
//设置坐标轴标签
|
|
|
|
|
|
_customPlot->xAxis->setLabel("x coordinates");
|
|
|
|
|
|
_customPlot->yAxis->setLabel("y coordinates");
|
|
|
|
|
|
//设置坐标轴范围,以便我们可以看到全部数据
|
|
|
|
|
|
_customPlot->xAxis->setRange(0, 1);
|
|
|
|
|
|
_customPlot->yAxis->setRange(0, 100);
|
|
|
|
|
|
_customPlot->replot();
|
|
|
|
|
|
#endif
|
2025-03-12 09:29:52 +00:00
|
|
|
|
// startTimer(1000);
|
2025-03-10 09:35:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-19 03:19:52 +00:00
|
|
|
|
CentralWidget::~CentralWidget()
|
|
|
|
|
|
{
|
2025-03-21 09:28:36 +00:00
|
|
|
|
FileManager::close();
|
2025-03-19 03:19:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-21 09:28:36 +00:00
|
|
|
|
void CentralWidget::setAnalysisMode(const CentralWidget::AnalysisMode mode)
|
2025-03-20 09:28:22 +00:00
|
|
|
|
{
|
2025-03-27 09:31:19 +00:00
|
|
|
|
#if 0
|
2025-03-21 09:28:36 +00:00
|
|
|
|
if(_nanlysisMode == mode){
|
|
|
|
|
|
return;
|
|
|
|
|
|
}else{
|
|
|
|
|
|
_nanlysisMode = mode;
|
|
|
|
|
|
}
|
2025-03-27 09:31:19 +00:00
|
|
|
|
#endif
|
2025-04-01 09:25:12 +00:00
|
|
|
|
_nanlysisMode = mode;
|
2025-03-20 09:28:22 +00:00
|
|
|
|
|
2025-03-21 09:28:36 +00:00
|
|
|
|
switch (mode)
|
|
|
|
|
|
{
|
|
|
|
|
|
case AnalysisMode::NumericalLabel:
|
2025-03-24 09:30:42 +00:00
|
|
|
|
case AnalysisMode::StartPoint:
|
|
|
|
|
|
case AnalysisMode::StopPoint:
|
|
|
|
|
|
case AnalysisMode::PeakSynthesisAnalysis:
|
2025-03-21 09:28:36 +00:00
|
|
|
|
setEventHandlerEnable(true);
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2025-03-20 09:28:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 09:29:52 +00:00
|
|
|
|
void CentralWidget::slotModeModify(const Global::Mode mode)
|
2025-03-10 09:35:07 +00:00
|
|
|
|
{
|
2025-03-13 09:27:31 +00:00
|
|
|
|
if (Global::Mode::ExperimentStart == mode)
|
2025-03-12 09:29:52 +00:00
|
|
|
|
{
|
2025-03-24 09:30:42 +00:00
|
|
|
|
if (_customPlot->graphCount() > 0 && _graph)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 清除第一个图表上的数据
|
|
|
|
|
|
_graph->setData(QVector<double>(), QVector<double>());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 09:29:52 +00:00
|
|
|
|
// 创建画布,设置画布上的点数据
|
2025-03-24 09:30:42 +00:00
|
|
|
|
// _graph = _customPlot->addGraph();
|
2025-03-12 09:29:52 +00:00
|
|
|
|
|
|
|
|
|
|
// 设置坐标轴标签
|
|
|
|
|
|
_customPlot->xAxis->setLabel("Temp/℃");
|
|
|
|
|
|
_customPlot->yAxis->setLabel("DSC/mW");
|
|
|
|
|
|
// 设置坐标轴范围,以便我们可以看到全部数据
|
|
|
|
|
|
_customPlot->xAxis->setRange(0, 400);
|
|
|
|
|
|
_customPlot->yAxis->setRange(-20, 20);
|
|
|
|
|
|
}
|
2025-03-13 09:27:31 +00:00
|
|
|
|
else if (Global::Mode::Analysis == mode)
|
2025-03-12 09:29:52 +00:00
|
|
|
|
{
|
2025-03-21 09:28:36 +00:00
|
|
|
|
qDebug() << "file close...";
|
|
|
|
|
|
FileManager::close();
|
2025-03-12 09:29:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-19 07:19:45 +00:00
|
|
|
|
void CentralWidget::slotRecvCommonData(const CommonData &cd)
|
2025-03-12 09:29:52 +00:00
|
|
|
|
{
|
2025-03-21 09:28:36 +00:00
|
|
|
|
qDebug() << "slotRevCommonData";
|
|
|
|
|
|
|
2025-03-12 09:29:52 +00:00
|
|
|
|
_customPlot->graph(0)->addData(cd.sample_temp, cd.dsc); // 添加数据到曲线
|
|
|
|
|
|
_customPlot->replot();
|
2025-03-31 09:24:48 +00:00
|
|
|
|
_customPlot->rescaleAxes();
|
2025-03-17 13:16:16 +00:00
|
|
|
|
//
|
|
|
|
|
|
FileManager::writeExperimentFile(cd);
|
2025-03-12 09:29:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-19 07:19:45 +00:00
|
|
|
|
void CentralWidget::slotRecvAnalysisFileName(const QString &fileName)
|
|
|
|
|
|
{
|
2025-03-21 09:28:36 +00:00
|
|
|
|
qDebug() << "slotRecvAnalysisFileName" << fileName;
|
2025-03-19 07:19:45 +00:00
|
|
|
|
|
2025-03-26 09:30:02 +00:00
|
|
|
|
// QVector<FileManager::ExperimentData> dataVtr;
|
|
|
|
|
|
_dataVtr.clear();
|
|
|
|
|
|
FileManager::readExperimentFile(fileName, _dataVtr);
|
2025-03-19 07:19:45 +00:00
|
|
|
|
|
2025-03-26 09:30:02 +00:00
|
|
|
|
if (_dataVtr.size() < 0)
|
2025-03-21 09:28:36 +00:00
|
|
|
|
{
|
2025-03-19 07:19:45 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-03-21 09:28:36 +00:00
|
|
|
|
|
2025-03-26 09:30:02 +00:00
|
|
|
|
PeakPoint::setExperimentData(_dataVtr);
|
|
|
|
|
|
|
2025-03-19 07:19:45 +00:00
|
|
|
|
// 设置坐标轴标签
|
|
|
|
|
|
_customPlot->yAxis->setLabel("DSC/mW");
|
|
|
|
|
|
_customPlot->xAxis->setLabel("Temp/℃");
|
|
|
|
|
|
// 设置坐标轴范围,以便我们可以看到全部数据
|
2025-03-31 09:24:48 +00:00
|
|
|
|
_customPlot->xAxis->setRange(0, 500);
|
2025-03-19 07:19:45 +00:00
|
|
|
|
_customPlot->yAxis->setRange(-20, 20);
|
|
|
|
|
|
|
2025-03-21 09:28:36 +00:00
|
|
|
|
QVector<double> xVtr, yVtr;
|
2025-03-26 09:30:02 +00:00
|
|
|
|
for (FileManager::ExperimentData &ed : _dataVtr)
|
2025-03-21 09:28:36 +00:00
|
|
|
|
{
|
2025-03-19 07:19:45 +00:00
|
|
|
|
xVtr.push_back(ed.sampleTemp);
|
|
|
|
|
|
yVtr.push_back(ed.dsc);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-21 09:28:36 +00:00
|
|
|
|
// 清除第一个图表上的数据
|
|
|
|
|
|
if (_customPlot->graphCount() > 0 && _graph)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 清除第一个图表上的数据
|
|
|
|
|
|
_graph->setData(QVector<double>(), QVector<double>());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_graph->addData(xVtr, yVtr);
|
2025-03-19 07:19:45 +00:00
|
|
|
|
_customPlot->replot();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-21 09:28:36 +00:00
|
|
|
|
void CentralWidget::slotAnalysisSettingApply()
|
|
|
|
|
|
{
|
2025-03-25 08:45:16 +00:00
|
|
|
|
switch (_nanlysisMode) {
|
|
|
|
|
|
case AnalysisMode::NumericalLabel:
|
|
|
|
|
|
{
|
2025-04-01 09:25:12 +00:00
|
|
|
|
QPointF selectPoint = PeakPoint::findClosestPointByX(
|
|
|
|
|
|
_line1->point1->coords().x());
|
|
|
|
|
|
|
|
|
|
|
|
drawText(selectPoint,PeakPoint::textFormatNumbericalLabel(selectPoint));
|
|
|
|
|
|
|
2025-03-25 08:45:16 +00:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case AnalysisMode::PeakSynthesisAnalysis:
|
|
|
|
|
|
{
|
|
|
|
|
|
double x1 = _line1->point1->coords().x();
|
|
|
|
|
|
double x2 = _line2->point1->coords().x();
|
2025-03-21 09:28:36 +00:00
|
|
|
|
|
2025-03-25 08:45:16 +00:00
|
|
|
|
fillGraph(x1,x2);
|
2025-03-26 09:30:02 +00:00
|
|
|
|
|
|
|
|
|
|
PeakPoint::setRegionPointX(x1,x2);
|
|
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
//enthalpy
|
|
|
|
|
|
double enthalpyValue = PeakPoint::calculateArea();
|
|
|
|
|
|
//peak
|
|
|
|
|
|
QPointF peakPoint = PeakPoint::findPeakPoint();
|
|
|
|
|
|
// qDebug()<<"peak point:"<<point;
|
|
|
|
|
|
//start point and end point
|
2025-04-01 09:25:12 +00:00
|
|
|
|
QPair<QPointF, QPointF> startEndPointPair =
|
|
|
|
|
|
PeakPoint::calculateStartAndEndPoint();
|
2025-03-27 09:31:19 +00:00
|
|
|
|
|
2025-04-01 09:25:12 +00:00
|
|
|
|
drawText(peakPoint,PeakPoint::textFormatPeakPoint(enthalpyValue,
|
|
|
|
|
|
peakPoint.x(),
|
|
|
|
|
|
startEndPointPair.first.x(),
|
|
|
|
|
|
startEndPointPair.second.x()));
|
2025-03-27 09:31:19 +00:00
|
|
|
|
//
|
|
|
|
|
|
break;
|
2025-03-25 08:45:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2025-03-21 09:28:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CentralWidget::slotAnalysisSettingConfirm()
|
|
|
|
|
|
{
|
2025-04-01 09:25:12 +00:00
|
|
|
|
slotAnalysisSettingApply();
|
|
|
|
|
|
setAnalysisMode(CentralWidget::AnalysisMode::None);
|
|
|
|
|
|
_line1->setVisible(false);
|
2025-03-21 09:28:36 +00:00
|
|
|
|
|
2025-04-01 09:25:12 +00:00
|
|
|
|
emit sigRightDockWidgetHide();
|
2025-03-21 09:28:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-24 09:30:42 +00:00
|
|
|
|
void CentralWidget::slotAnalysisSettingUndo()
|
|
|
|
|
|
{
|
2025-04-01 09:25:12 +00:00
|
|
|
|
clearData(ClearDataMode::Undo);
|
2025-03-24 09:30:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CentralWidget::slotAnalysisSettingCancel()
|
|
|
|
|
|
{
|
2025-04-01 09:25:12 +00:00
|
|
|
|
clearData(ClearDataMode::Undo);
|
|
|
|
|
|
setAnalysisMode(CentralWidget::AnalysisMode::None);
|
|
|
|
|
|
_line1->setVisible(false);
|
2025-03-24 09:30:42 +00:00
|
|
|
|
|
2025-04-01 09:25:12 +00:00
|
|
|
|
emit sigRightDockWidgetHide();
|
2025-03-24 09:30:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CentralWidget::slotAnalysisSettingLineXPoint(const int index, const double)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 09:29:52 +00:00
|
|
|
|
void CentralWidget::timerEvent(QTimerEvent *event)
|
|
|
|
|
|
{
|
|
|
|
|
|
// key的单位是秒
|
2025-03-10 09:35:07 +00:00
|
|
|
|
double key = QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000.0;
|
2025-03-12 09:29:52 +00:00
|
|
|
|
// 添加数据
|
|
|
|
|
|
// 使用随机数产生一条曲线
|
|
|
|
|
|
// double value0 = realDataI();
|
2025-03-10 09:35:07 +00:00
|
|
|
|
double value0 = QRandomGenerator::global()->bounded(10.123);
|
2025-03-12 09:29:52 +00:00
|
|
|
|
_customPlot->graph(0)->addData(key, value0); // 添加数据到曲线
|
2025-03-10 09:35:07 +00:00
|
|
|
|
|
2025-03-12 09:29:52 +00:00
|
|
|
|
// 删除8秒之前的数据。这里的8要和下面设置横坐标宽度的8配合起来
|
|
|
|
|
|
// 才能起到想要的效果,可以调整这两个值,观察显示的效果。
|
2025-03-10 09:35:07 +00:00
|
|
|
|
_customPlot->graph(0)->data()->remove(key - 80);
|
2025-03-12 09:29:52 +00:00
|
|
|
|
// 自动设定graph(1)曲线y轴的范围,如果不设定,有可能看不到图像
|
|
|
|
|
|
// 也可以用ui->customPlot->yAxis->setRange(up,low)手动设定y轴范围
|
2025-03-10 09:35:07 +00:00
|
|
|
|
_customPlot->graph(0)->rescaleValueAxis(true);
|
|
|
|
|
|
|
2025-03-12 09:29:52 +00:00
|
|
|
|
// 这里的8,是指横坐标时间宽度为8秒,如果想要横坐标显示更多的时间
|
|
|
|
|
|
// 就把8调整为比较大到值,比如要显示60秒,那就改成60。
|
|
|
|
|
|
// 这时removeDataBefore(key-8)中的8也要改成60,否则曲线显示不完整。
|
2025-03-10 09:35:07 +00:00
|
|
|
|
|
2025-03-12 09:29:52 +00:00
|
|
|
|
_customPlot->yAxis->setRange(0, 20); // 设定x轴的范围
|
|
|
|
|
|
_customPlot->xAxis->setRange(key + 0.25, 80, Qt::AlignRight); // 设定x轴的范围
|
2025-03-10 09:35:07 +00:00
|
|
|
|
_customPlot->replot();
|
|
|
|
|
|
}
|
2025-03-12 09:29:52 +00:00
|
|
|
|
|
2025-03-21 09:28:36 +00:00
|
|
|
|
void CentralWidget::contextMenuEvent(QContextMenuEvent *event)
|
2025-03-20 09:28:22 +00:00
|
|
|
|
{
|
2025-03-21 09:28:36 +00:00
|
|
|
|
qDebug()<<"left menu...";
|
|
|
|
|
|
QPoint point = event->globalPos();
|
|
|
|
|
|
emit sigContextMenuShow(point);
|
|
|
|
|
|
}
|
2025-03-20 09:28:22 +00:00
|
|
|
|
|
2025-03-21 09:28:36 +00:00
|
|
|
|
void CentralWidget::setEventHandlerEnable(const bool flag)
|
|
|
|
|
|
{
|
2025-03-27 09:31:19 +00:00
|
|
|
|
logde<<"setEventHandlerEnable..."<<flag;
|
|
|
|
|
|
|
|
|
|
|
|
// todo. 当竖线隐藏时,需要设置不可选择模式。
|
2025-03-21 09:28:36 +00:00
|
|
|
|
_eventHandler->setEnable(flag);
|
2025-03-25 08:45:16 +00:00
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
_line1->setVisible(flag);
|
2025-03-21 09:28:36 +00:00
|
|
|
|
if(AnalysisMode::NumericalLabel != _nanlysisMode){
|
|
|
|
|
|
_line2->setVisible(flag);
|
2025-03-20 09:28:22 +00:00
|
|
|
|
}
|
2025-03-21 09:28:36 +00:00
|
|
|
|
_customPlot->replot();
|
2025-03-20 09:28:22 +00:00
|
|
|
|
}
|
2025-03-27 09:31:19 +00:00
|
|
|
|
|
2025-03-26 09:30:02 +00:00
|
|
|
|
void CentralWidget::drawText(const QPointF point, const QString text)
|
2025-03-24 09:30:42 +00:00
|
|
|
|
{
|
2025-03-26 09:30:02 +00:00
|
|
|
|
// double y = PeakPoint::findClosestY(x);
|
|
|
|
|
|
// 创建标注文字(QCPItemText)
|
|
|
|
|
|
QCPItemText *textLabel = new QCPItemText(_customPlot);
|
|
|
|
|
|
textLabel->setPositionAlignment(Qt::AlignBottom | Qt::AlignHCenter); // 对齐方式
|
|
|
|
|
|
textLabel->position->setType(QCPItemPosition::ptPlotCoords); // 使用数据坐标
|
|
|
|
|
|
textLabel->position->setCoords(point.x() + 20, point.y()); // 设置文本位置在指定点上方
|
|
|
|
|
|
|
|
|
|
|
|
textLabel->setText(text); // 设置文本内容
|
|
|
|
|
|
// textLabel->setFont(QFont("Arial", 10));
|
|
|
|
|
|
textLabel->setPen(QPen(Qt::lightGray)); // 文字边框
|
|
|
|
|
|
textLabel->setBrush(Qt::white); // 文字背景
|
|
|
|
|
|
|
|
|
|
|
|
// 创建指向点的线段(QCPItemLine)
|
|
|
|
|
|
QCPItemLine *arrow = new QCPItemLine(_customPlot);
|
|
|
|
|
|
arrow->start->setParentAnchor(textLabel->left); // 线段起点绑定到标注文字底部
|
|
|
|
|
|
arrow->end->setCoords(point.x(),point.y()); // 线段终点设置为指定的点
|
|
|
|
|
|
arrow->setHead(QCPLineEnding::esSpikeArrow); // 添加箭头
|
|
|
|
|
|
arrow->setPen(QPen(Qt::red, 1));
|
|
|
|
|
|
|
|
|
|
|
|
// 重绘图表以显示文本标签和箭头
|
|
|
|
|
|
_customPlot->replot();
|
|
|
|
|
|
|
2025-03-24 09:30:42 +00:00
|
|
|
|
#if 0
|
|
|
|
|
|
// 创建标注文字(QCPItemText)
|
|
|
|
|
|
QCPItemText *textLabel = new QCPItemText(_customPlot);
|
|
|
|
|
|
textLabel->setPositionAlignment(Qt::AlignBottom|Qt::AlignHCenter); // 对齐方式
|
|
|
|
|
|
textLabel->position->setType(QCPItemPosition::ptPlotCoords); // 使用数据坐标
|
|
|
|
|
|
textLabel->position->setCoords(x,
|
|
|
|
|
|
_graph->data()->at(x)->value + 0.5); // 假设标注在 x=5 的点上方
|
|
|
|
|
|
textLabel->setText("标注文字");
|
|
|
|
|
|
textLabel->setFont(QFont("Arial", 10));
|
|
|
|
|
|
textLabel->setPen(QPen(Qt::black)); // 文字边框
|
|
|
|
|
|
textLabel->setBrush(Qt::white); // 文字背景
|
|
|
|
|
|
|
|
|
|
|
|
// 创建指向点的线段(QCPItemLine)
|
|
|
|
|
|
QCPItemLine *arrow = new QCPItemLine(_customPlot);
|
|
|
|
|
|
arrow->start->setParentAnchor(textLabel->bottom); // 线段起点绑定到标注文字底部
|
|
|
|
|
|
arrow->end->setCoords(x, _graph->data()->at(x)->value); // 线段终点绑定到数据点
|
|
|
|
|
|
arrow->setHead(QCPLineEnding::esSpikeArrow); // 添加箭头
|
|
|
|
|
|
arrow->setPen(QPen(Qt::red, 2));
|
|
|
|
|
|
#endif
|
2025-03-25 08:45:16 +00:00
|
|
|
|
|
|
|
|
|
|
#if 0
|
2025-03-24 09:30:42 +00:00
|
|
|
|
if (!_graph || !_customPlot) {
|
2025-03-25 08:45:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 创建标注文字(QCPItemText)
|
|
|
|
|
|
QCPItemText *textLabel = new QCPItemText(_customPlot);
|
|
|
|
|
|
textLabel->setPositionAlignment(Qt::AlignBottom|Qt::AlignHCenter); // 对齐方式
|
|
|
|
|
|
textLabel->position->setType(QCPItemPosition::ptPlotCoords); // 使用数据坐标
|
|
|
|
|
|
|
|
|
|
|
|
// 查找最接近 x 的数据点
|
|
|
|
|
|
auto it = _graph->data()->findBegin(x);
|
|
|
|
|
|
if (it != _graph->data()->end()) {
|
|
|
|
|
|
double y = it->value + 0.5;
|
|
|
|
|
|
textLabel->position->setCoords(x, y);
|
|
|
|
|
|
textLabel->setText(text);
|
|
|
|
|
|
textLabel->setFont(QFont("Arial", 10));
|
|
|
|
|
|
textLabel->setPen(QPen(Qt::black)); // 文字边框
|
|
|
|
|
|
textLabel->setBrush(Qt::white); // 文字背景
|
|
|
|
|
|
|
|
|
|
|
|
// 创建指向点的线段(QCPItemLine)
|
|
|
|
|
|
QCPItemLine *arrow = new QCPItemLine(_customPlot);
|
|
|
|
|
|
arrow->start->setParentAnchor(textLabel->bottom); // 线段起点绑定到标注文字底部
|
|
|
|
|
|
arrow->end->setCoords(x, it->value); // 线段终点绑定到数据点
|
|
|
|
|
|
arrow->setHead(QCPLineEnding::esSpikeArrow); // 添加箭头
|
|
|
|
|
|
arrow->setPen(QPen(Qt::red, 2));
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-26 09:30:02 +00:00
|
|
|
|
#if 0
|
2025-03-25 08:45:16 +00:00
|
|
|
|
double CentralWidget::findClosestY(double targetX) {
|
|
|
|
|
|
// 获取曲线数据容器
|
2025-03-26 09:30:02 +00:00
|
|
|
|
QSharedPointer<QCPDataContainer<QCPGraphData>> dataContainer =
|
|
|
|
|
|
_graph->data();
|
2025-03-25 08:45:16 +00:00
|
|
|
|
// 初始化最小差值和对应的 y 值
|
|
|
|
|
|
double minDiff = std::numeric_limits<double>::max();
|
|
|
|
|
|
double closestY = 0.0;
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历数据容器
|
|
|
|
|
|
for (int i = 0; i < dataContainer->size(); ++i) {
|
|
|
|
|
|
double currentX = dataContainer->at(i)->key;
|
|
|
|
|
|
double currentY = dataContainer->at(i)->value;
|
|
|
|
|
|
|
|
|
|
|
|
// 计算当前 x 与目标 x 的差值的绝对值
|
|
|
|
|
|
double diff = std::abs(currentX - targetX);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新最小差值和对应的 y 值
|
|
|
|
|
|
if (diff < minDiff) {
|
|
|
|
|
|
minDiff = diff;
|
|
|
|
|
|
closestY = currentY;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return closestY;
|
|
|
|
|
|
}
|
2025-03-26 09:30:02 +00:00
|
|
|
|
#endif
|
2025-03-25 08:45:16 +00:00
|
|
|
|
|
|
|
|
|
|
void CentralWidget::fillGraph(const double x1, const double x2)
|
|
|
|
|
|
{
|
2025-03-26 09:30:02 +00:00
|
|
|
|
//todo.未寻找x1\x2之间最大值。
|
|
|
|
|
|
|
2025-04-01 09:25:12 +00:00
|
|
|
|
double y1 = PeakPoint::findClosestPointByX(x1).y();
|
|
|
|
|
|
double y2 = PeakPoint::findClosestPointByX(x2).y();
|
2025-03-25 08:45:16 +00:00
|
|
|
|
|
|
|
|
|
|
QVector<double> xVtr,yVtr;
|
|
|
|
|
|
xVtr.push_back(x1);
|
|
|
|
|
|
xVtr.push_back(x2);
|
|
|
|
|
|
|
|
|
|
|
|
yVtr.push_back(y1);
|
|
|
|
|
|
yVtr.push_back(y2);
|
|
|
|
|
|
|
|
|
|
|
|
QCPGraph *mainGraph = _customPlot->addGraph();
|
|
|
|
|
|
mainGraph->setData(xVtr, yVtr);
|
|
|
|
|
|
|
|
|
|
|
|
// 样式配置
|
|
|
|
|
|
mainGraph->setPen(QPen(Qt::red, 1));
|
|
|
|
|
|
|
|
|
|
|
|
_graph->setBrush(QBrush(Qt::lightGray));
|
|
|
|
|
|
_graph->setChannelFillGraph(mainGraph);
|
|
|
|
|
|
|
|
|
|
|
|
// customPlot->graph(0)->setChannelFillGraph(customPlot->graph(1));
|
|
|
|
|
|
// _customPlot->graph(1);
|
|
|
|
|
|
_customPlot->replot();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-01 09:25:12 +00:00
|
|
|
|
void CentralWidget::clearData(const CentralWidget::ClearDataMode mode)
|
2025-03-25 08:45:16 +00:00
|
|
|
|
{
|
2025-04-01 09:25:12 +00:00
|
|
|
|
if(mode == ClearDataMode::All){
|
|
|
|
|
|
// Clear the data of graph.
|
|
|
|
|
|
if (_customPlot->graphCount() > 0 && _graph)
|
|
|
|
|
|
{
|
|
|
|
|
|
_graph->setData(QVector<double>(), QVector<double>());
|
|
|
|
|
|
}
|
2025-03-27 09:31:19 +00:00
|
|
|
|
|
2025-04-01 09:25:12 +00:00
|
|
|
|
// Set lines visiable false.
|
|
|
|
|
|
_line1->setVisible(false);
|
|
|
|
|
|
_line2->setVisible(false);
|
2025-03-27 09:31:19 +00:00
|
|
|
|
}
|
2025-04-01 09:25:12 +00:00
|
|
|
|
|
|
|
|
|
|
// Clear filled area.
|
2025-03-27 09:31:19 +00:00
|
|
|
|
_graph->setBrush(QBrush(Qt::transparent));
|
|
|
|
|
|
|
|
|
|
|
|
// Clear graph on plot.
|
|
|
|
|
|
for (int i = _customPlot->graphCount() - 1; i >= 0; --i) {
|
|
|
|
|
|
QCPGraph *graph = _customPlot->graph(i);
|
|
|
|
|
|
if (graph != _graph) {
|
|
|
|
|
|
_customPlot->removeGraph(graph);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// Delete items.
|
|
|
|
|
|
QList<QCPAbstractItem *> itemsToKeep;
|
|
|
|
|
|
itemsToKeep << _line1 << _line2;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = _customPlot->itemCount() - 1; i >= 0; --i) {
|
|
|
|
|
|
QCPAbstractItem *item = _customPlot->item(i);
|
|
|
|
|
|
if (!itemsToKeep.contains(item)) {
|
|
|
|
|
|
_customPlot->removeItem(item);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重绘图表以显示更改
|
|
|
|
|
|
_customPlot->replot();
|
2025-04-01 09:25:12 +00:00
|
|
|
|
}
|
2025-03-25 08:45:16 +00:00
|
|
|
|
|
2025-04-01 09:25:12 +00:00
|
|
|
|
void CentralWidget::clearAllData()
|
|
|
|
|
|
{
|
|
|
|
|
|
clearData(ClearDataMode::All);
|
2025-03-24 09:30:42 +00:00
|
|
|
|
}
|