#include #include #include #include #include #include "centralwidget.h" #include "filemanager.h" #include "pointcalculate.h" #include "logger.h" CentralWidget::CentralWidget(QWidget *parent) : QWidget(parent), _customPlot(new QCustomPlot(this)) ,_analysisMode(AnalysisMode::None) { setMouseTracking(true); setStyleSheet("background-color: lightgray;"); resize(888, 666); QHBoxLayout *layout = new QHBoxLayout(); layout->setMargin(0); layout->addWidget(_customPlot); this->setLayout(layout); // 创建两条竖线 _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); // 安装事件过滤器 // _graph = _customPlot->addGraph(0); // _eventHandler = new EventHandler(_customPlot, _line1, _line2, _graph, nullptr); _eventHandler = new EventHandler(_customPlot, _line1, _line2, nullptr); _eventHandler->setEnable(true); _customPlot->installEventFilter(_eventHandler); _customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); connect(_eventHandler,&EventHandler::sigSendLineXCoord, this,&CentralWidget::sigSendLineXCoord); // connect(_customPlot, &QCustomPlot::selectionChangedByUser, // this, &CentralWidget::slotSelectionChanged); setEventHandlerEnable(false); // #if 0 // init data QVector 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 // startTimer(1000); } CentralWidget::~CentralWidget() { FileManager::close(); } void CentralWidget::setAnalysisMode(const CentralWidget::AnalysisMode mode) { _analysisMode = mode; switch (mode) { case AnalysisMode::NumericalLabel: case AnalysisMode::StartPoint: case AnalysisMode::StopPoint: case AnalysisMode::PeakSynthesisAnalysis: case AnalysisMode::GlassTransition: setEventHandlerEnable(true); break; default: break; } } void CentralWidget::slotModeModify(const Global::Mode mode) { if (Global::Mode::ExperimentStart == mode) { #if 0 if (_customPlot->graphCount() > 0 && _currentGraph) { // 清除第一个图表上的数据 _currentGraph->setData(QVector(), QVector()); } #endif // 创建画布,设置画布上的点数据 // _graph = _customPlot->addGraph(); // 设置坐标轴标签 _customPlot->xAxis->setLabel("Temp/℃"); _customPlot->yAxis->setLabel("DSC/mW"); // 设置坐标轴范围,以便我们可以看到全部数据 _customPlot->xAxis->setRange(0, 400); _customPlot->yAxis->setRange(-20, 20); } else if (Global::Mode::Analysis == mode) { qDebug() << "file close..."; FileManager::close(); } } void CentralWidget::slotRecvCommonData(const CommonData &cd) { qDebug() << "slotRevCommonData"; _customPlot->graph(0)->addData(cd.sample_temp, cd.dsc); // 添加数据到曲线 _customPlot->replot(); _customPlot->rescaleAxes(); // FileManager::writeExperimentFile(cd); } void CentralWidget::slotRecvAnalysisFileName(const QString &fileName) { qDebug() << "slotRecvAnalysisFileName" << fileName; // // clearData(ClearDataMode::All); // _dataVtr.clear(); FileManager::readExperimentFile(fileName, _dataVtr); if (_dataVtr.size() < 0) { return; } // // _customPlot->xAxis->setRange(0, 500); // _customPlot->yAxis->setRange(-20, 20); PointCalculate::setExperimentData(_dataVtr); QPairstartEndPointPair = PointCalculate::getStartAndEndPoint(); QPointF endPoint = startEndPointPair.second; _customPlot->xAxis->setRange(0, endPoint.x() / 3 * 4); QPointF peakPoint = PointCalculate::getPeakPoint(); float absY = std::abs(peakPoint.y()); _customPlot->yAxis->setRange(- absY * 2,absY *2); // 设置坐标轴标签 _customPlot->yAxis->setLabel("DSC/mW"); _customPlot->xAxis->setLabel("Temp/℃"); QVector tVtr,xVtr, yVtr; int index = 0; for (FileManager::ExperimentData &ed : _dataVtr) { tVtr.push_back(index++); xVtr.push_back(ed.sampleTemp); yVtr.push_back(ed.dsc); } _currentCurve = new QCPCurve(_customPlot->xAxis, _customPlot->yAxis); _currentCurve->setData(tVtr, xVtr, yVtr); // _currentCurve->setPen(QPen(Qt::red)); // 设置线条颜色为红色 // _currentCurve->setBrush(QBrush(QColor(255, 0, 0, 20))); // 设置填充颜色并带有透明度 _currentCurve->setSelectable(QCP::stWhole); // 设置曲线可选 // _currentCurve->setSelectable(QCP::stPlottable); // 设置曲线可选 Global::instance()->_curveDataVtr.push_back( qMakePair>( _currentCurve,_dataVtr)); // 清除第一个图表上的数据 #if 0 if (_customPlot->graphCount() > 0 && _graph) { // 清除第一个图表上的数据 _graph->setData(QVector(), QVector()); } #endif #if 0 _currentGraph = _customPlot->addGraph(); _graphVtr.push_back(_currentGraph); _currentGraph->addData(xVtr, yVtr); #endif _customPlot->replot(); } void CentralWidget::slotSelectionChanged() { logde<<"selectedPlottables:"<< _customPlot->selectedPlottables().size(); logde<<"selectedGraphs:"<< _customPlot->selectedGraphs().size(); logde<<"selectedItems:"<< _customPlot->selectedItems().size(); logde<<"plottableCount:"<< _customPlot->plottableCount(); return; for(int i = 0;i < _customPlot->plottableCount(); i++) { QCPCurve *curve = qobject_cast(_customPlot->plottable(i)); if(curve){ if (curve->selected()) { logde<<"selected..."; curve->setPen(QPen(Qt::green)); _customPlot->replot(); } else { curve->setPen(QPen(Qt::blue)); _customPlot->replot(); } } logde << "Current pen color:" << curve->pen().color().name().toStdString(); } // _customPlot->replot(); // _customPlot->update(); #if 0 for (QCPAbstractPlottable *plottable : _customPlot->plottable()) { QCPCurve *curve = qobject_cast(plottable); if (curve) { if (curve->selected()) { // 曲线被选中,设置为橙色 curve->setPen(QPen(Qt::green)); } else { #if 0 // 曲线未被选中,恢复默认颜色 if (curve == _curve1) { curve->setPen(QPen(Qt::blue)); } else if (curve == _curve2) { curve->setPen(QPen(Qt::red)); } #endif } } } #endif #if 0 // 检查是否有曲线被选中 if (_customPlot->selectedPlottables().size() > 0) { QCPCurve *selectedCurve = qobject_cast(_customPlot->selectedPlottables().first()); if (selectedCurve) { selectedCurve->setPen(QPen(Qt::green)); #if 0 // 弹出颜色选择对话框 QColor color = QColorDialog::getColor(selectedCurve->pen().color(), this); if (color.isValid()) { // 改变曲线颜色 selectedCurve->setPen(QPen(color)); } #endif }else{ } } #endif } void CentralWidget::slotAnalysisSettingApply() { switch (_analysisMode) { case AnalysisMode::NumericalLabel: { QPointF selectPoint = PointCalculate::getClosestPointByX( _line1->point1->coords().x()); drawText(selectPoint,PointCalculate::textFormatNumbericalLabel(selectPoint)); break; } case AnalysisMode::StartPoint: case AnalysisMode::StopPoint:{ double x1 = _line1->point1->coords().x(); double x2 = _line2->point1->coords().x(); PointCalculate::setRegionPointX(x1,x2); QPair startEndPointPair = PointCalculate::calculateStartAndEndPoint(); if(_analysisMode == AnalysisMode::StartPoint){ drawText(startEndPointPair.first, PointCalculate::textFormatStartPoint(startEndPointPair.first)); }else{ drawText(startEndPointPair.second, PointCalculate::textFormatEndPoint(startEndPointPair.second)); } break; } case AnalysisMode::PeakSynthesisAnalysis: { double x1 = _line1->point1->coords().x(); double x2 = _line2->point1->coords().x(); fillGraph(x1,x2); PointCalculate::setRegionPointX(x1,x2); //enthalpy double enthalpyValue = PointCalculate::calculateArea(); //peak QPointF peakPoint = PointCalculate::getPeakPoint(); //start point and end point QPair startEndPointPair = PointCalculate::calculateStartAndEndPoint(); logde<<"start,end:"<setVisible(false); _line2->setVisible(false); emit sigRightDockWidgetHide(); } void CentralWidget::slotAnalysisSettingUndo() { clearData(ClearDataMode::Undo); } void CentralWidget::slotAnalysisSettingCancel() { clearData(ClearDataMode::Undo); setAnalysisMode(CentralWidget::AnalysisMode::None); _line1->setVisible(false); _line2->setVisible(false); emit sigRightDockWidgetHide(); } void CentralWidget::slotAnalysisSettingLineXPoint(const int index, const double) { } void CentralWidget::timerEvent(QTimerEvent *event) { // key的单位是秒 double key = QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000.0; // 添加数据 // 使用随机数产生一条曲线 // double value0 = realDataI(); double value0 = QRandomGenerator::global()->bounded(10.123); _customPlot->graph(0)->addData(key, value0); // 添加数据到曲线 // 删除8秒之前的数据。这里的8要和下面设置横坐标宽度的8配合起来 // 才能起到想要的效果,可以调整这两个值,观察显示的效果。 _customPlot->graph(0)->data()->remove(key - 80); // 自动设定graph(1)曲线y轴的范围,如果不设定,有可能看不到图像 // 也可以用ui->customPlot->yAxis->setRange(up,low)手动设定y轴范围 _customPlot->graph(0)->rescaleValueAxis(true); // 这里的8,是指横坐标时间宽度为8秒,如果想要横坐标显示更多的时间 // 就把8调整为比较大到值,比如要显示60秒,那就改成60。 // 这时removeDataBefore(key-8)中的8也要改成60,否则曲线显示不完整。 _customPlot->yAxis->setRange(0, 20); // 设定x轴的范围 _customPlot->xAxis->setRange(key + 0.25, 80, Qt::AlignRight); // 设定x轴的范围 _customPlot->replot(); } void CentralWidget::contextMenuEvent(QContextMenuEvent *event) { qDebug()<<"left menu..."; QPoint point = event->globalPos(); emit sigContextMenuShow(point); } void CentralWidget::glassTransitionHandle() { QPointF point1 = PointCalculate::getClosestPointByX(_line1->point1->coords().x()); QPointF point2 = PointCalculate::getClosestPointByX(_line2->point1->coords().x()); logde<<"point1:"<point1->setCoords(point1.x() - 5,point1.y()); line1->point2->setCoords(point1.x() + 5,point1.y()); line1->setPen(QPen(Qt::darkRed)); line1->setSelectable(false); line1->setVisible(true); QCPItemStraightLine *line2 = new QCPItemStraightLine(_customPlot); line2->point1->setCoords(point2.x() - 5,point2.y()); line2->point2->setCoords(point2.x() + 5,point2.y()); line2->setPen(QPen(Qt::darkGreen)); line2->setSelectable(false); line2->setVisible(true); _customPlot->replot(); #endif // PointCalculate::LineStruct lineStrc1,lineStrc2,tangetLineStrc; lineStrc1.slope = 0.0; lineStrc1.intercept = point1.y(); lineStrc2.slope = 0.0; lineStrc2.intercept = point2.y(); QPair tangentLinePair = PointCalculate::getCurveInflectionPointTangent(point1.x(),point2.x()); tangetLineStrc.slope = tangentLinePair.first; tangetLineStrc.intercept = tangentLinePair.second; QPointF intersection1 = PointCalculate::getIntersectionBySlope(tangetLineStrc,lineStrc1); QPointF intersection2 = PointCalculate::getIntersectionBySlope(tangetLineStrc,lineStrc2); // logde<<"intersection1 x:"<addItem(circle); // 设置圆形的位置和大小 circle->topLeft->setCoords(-5, 5); circle->bottomRight->setCoords(5, -5); // 设置圆形的填充和边框颜色 circle->setBrush(QBrush(Qt::cyan)); circle->setPen(QPen(Qt::blue)); #endif #if 0 QCPItemStraightLine *line3 = new QCPItemStraightLine(_customPlot); line3->point1->setCoords(averagePoint.x() + 1,averagePoint.y() + 1); line3->point2->setCoords(averagePoint.x() - 1,averagePoint.y() - 1); line3->setPen(QPen(Qt::black)); line3->setSelectable(false); line3->setVisible(true); _customPlot->replot(); #endif } void CentralWidget::setEventHandlerEnable(const bool flag) { logde<<"setEventHandlerEnable..."<setSelected(flag); line->setVisible(flag); }; // todo. 当竖线隐藏时,需要设置不可选择模式。 // _eventHandler->setEnable(flag); #if 1 // move line to suitable position. double xMax = _customPlot->xAxis->range().upper; // X 轴的最大值 logde<<"xMax:"<point1->setCoords(xMax / 3,_line1->point1->coords().y()); _line1->point2->setCoords(xMax / 3,_line1->point2->coords().y()); _line2->point1->setCoords(xMax / 3 * 2,_line2->point1->coords().y()); _line2->point2->setCoords(xMax / 3 * 2,_line2->point2->coords().y()); #endif lineVisiableFunc(_line1); if(AnalysisMode::NumericalLabel != _analysisMode){ lineVisiableFunc(_line2); } // _customPlot->replot(); } void CentralWidget::drawText(const QPointF point, const QString text) { // 创建标注文字(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(); } void CentralWidget::fillGraph(const double x1, const double x2) { //todo.未寻找x1\x2之间最大值。 double y1 = PointCalculate::getClosestPointByX(x1).y(); double y2 = PointCalculate::getClosestPointByX(x2).y(); QVector 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)); #if 0 _currentGraph->setBrush(QBrush(Qt::lightGray)); _currentGraph->setChannelFillGraph(mainGraph); #endif // customPlot->graph(0)->setChannelFillGraph(customPlot->graph(1)); // _customPlot->graph(1); _customPlot->replot(); } void CentralWidget::clearData(const CentralWidget::ClearDataMode mode) { if(mode == ClearDataMode::All){ // Clear the data of graph. #if 0 if (_customPlot->graphCount() > 0 && _currentGraph) { _currentGraph->setData(QVector(), QVector()); } #endif // Set lines visiable false. _line1->setVisible(false); _line2->setVisible(false); } #if 0 // Clear filled area. if(_currentGraph){ _currentGraph->setBrush(QBrush(Qt::transparent)); } // Clear graph on plot. for (int i = _customPlot->graphCount() - 1; i >= 0; --i) { QCPGraph *graph = _customPlot->graph(i); if (graph != _currentGraph) { _customPlot->removeGraph(graph); } } #endif // Delete items. QList 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(); } void CentralWidget::clearAllData() { clearData(ClearDataMode::All); }