话不多说。
效果:(动图依次展示:①点击曲线显示坐标->②平移->③缩放->④双击还原)
第一步:自定义QChartView,直接搬
FirtCurveChartView.h
#ifndef FITCURVECHARTVIEW_H#define FITCURVECHARTVIEW_H#include <QtCharts>class FitCurveChartView : public QChartView { Q_OBJECTpublic: FitCurveChartView(QWidget *parent = Q_NULLPTR); ~FitCurveChartView();protected: void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseDoubleClickEvent(QMouseEvent *event); void wheelEvent(QWheelEvent *event);signals: void signalMouseEvent(int eventId, QMouseEvent *event); void signalWheelEvent(QWheelEvent *event);};#endif // FITCURVECHARTVIEW_H
FirtCurveChartView.cpp
#include "FitCurveChartView.h"FitCurveChartView::FitCurveChartView(QWidget *parent) {}FitCurveChartView::~FitCurveChartView() {}void FitCurveChartView::mousePressEvent(QMouseEvent *event) { emit signalMouseEvent(0, event); QChartView::mousePressEvent(event);}void FitCurveChartView::mouseMoveEvent(QMouseEvent *event) { emit signalMouseEvent(1, event); QChartView::mouseMoveEvent(event);}void FitCurveChartView::mouseReleaseEvent(QMouseEvent *event) { emit signalMouseEvent(2, event); QChartView::mouseReleaseEvent(event);}void FitCurveChartView::mouseDoubleClickEvent(QMouseEvent *event) { emit signalMouseEvent(3, event); QChartView::mouseDoubleClickEvent(event);}void FitCurveChartView::wheelEvent(QWheelEvent *event) { emit signalWheelEvent(event); QChartView::wheelEvent(event);}
第二步:在主界面代码中使用,我的是在自定义对话框里面,你们可以直接在窗口中使用
举例:fitcurvedialog.h
#ifndef FITCURVEDIALOG_H#define FITCURVEDIALOG_H#include <QDialog>#include "FitCurveChartView.h"namespace Ui {class FitCurveDialog;}class FitCurveDialog : public QDialog{ Q_OBJECTpublic: explicit FitCurveDialog(QWidget *parent = nullptr); ~FitCurveDialog(); void initQChartView(); void updateXYGuideLine(); void resetZoomAndScroll(); QVector<int> getAxisRanges();public slots: void theSlotMouseEvent(int eventId, QMouseEvent *event); void theSlotWheelEvent(QWheelEvent *event);private: Ui::FitCurveDialog *ui; FitCurveChartView *curveChartView; QChart *curveChart; QSplineSeries* fitPointsSeriesS; //要显示的曲线原始数据 QScatterSeries* tipSeries; QSplineSeries* xGuideSeries; //鼠标悬浮位置点的x轴辅助线 QSplineSeries* yGuideSeries; //鼠标悬浮位置点的y轴辅助线 bool isPressed = false; //图标是否在拖拽中 QPoint pressedPoint; //鼠标拖拽起点};#endif // FITCURVEDIALOG_H
fitcurvedialog.cpp (UI文件里面就放了一个水平布局chartLayout)
#include "fitcurvedialog.h"#include "ui_fitcurvedialog.h"FitCurveDialog::FitCurveDialog(QWidget *parent) : QDialog(parent), ui(new Ui::FitCurveDialog){ ui->setupUi(this); qApp->setOverrideCursor(Qt::ArrowCursor); //允许系统弹窗、提示 initQChartView();}void FitCurveDialog::initQChartView() { //创建图表框架 curveChartView = new FitCurveChartView(this); curveChartView->setMaximumWidth(1730); curveChartView->setMinimumHeight(480); curveChart = new QChart(); curveChart->setTheme(QChart::ChartThemeBlueIcy); curveChart->setContentsMargins(0, 0, 0, 0); //设置外边界全部为0, 根据自己实际情况设置 curveChart->setMargins(QMargins(5, -30, 5, 10)); //设置内边界, 根据自己实际情况设置 curveChart->setBackgroundRoundness(0); //设置表格边框圆角半径 curveChartView->setChart(curveChart); //创建折线序列 fitPointsSeriesS = new QSplineSeries(this); //原始数据曲线 fitPointsSeriesS->setUseOpenGL(true); xGuideSeries = new QSplineSeries(this); yGuideSeries = new QSplineSeries(this); tipSeries = new QScatterSeries(); // 创建一个散点数据集对象,用于显示 tipSeries->setMarkerShape(QScatterSeries::MarkerShapeCircle); // 设置绘制的散点的样式为圆 tipSeries->setMarkerSize(10); QObject::connect(fitPointsSeriesS, &QSplineSeries::clicked, [=](const QPointF &point)mutable{ QPointF tempPoint; QVector<QPointF> tempList(fitPointsSeriesS->pointsVector()); //复制曲线中的数据进行计算, 因为直接使用会导致卡顿 int tempX = qRound(point.x()); int tempY = -999; for (int i = 0; i < tempList.size(); i++) { if (tempList[i].x() == tempX) { tempY = tempList[i].y(); tempPoint.setX(tempX); tempPoint.setY(tempY); break; } } if (tempY != -999) { QToolTip::showText(QCursor::pos(), QString("(%1,%2)").arg(tempX).arg(tempY)); QVector<QPointF> tipList; tipList.append(tempPoint); tipSeries->replace(tipList); updateXYGuideLine(); } }); curveChart->addSeries(xGuideSeries); curveChart->addSeries(yGuideSeries); curveChart->addSeries(fitPointsSeriesS); curveChart->addSeries(tipSeries); //添加数据绘制 size_t count = 20000; QVector<QPointF> list; for (size_t i = 0; i < count; i++) { list.append(QPoint(i, int(i / 40))); } fitPointsSeriesS->replace(list); //创建坐标轴 QValueAxis* axisX = new QValueAxis; axisX->setRange(0, 20000); axisX->setTickCount(21); axisX->setLabelFormat("%d"); axisX->setLabelsAngle(-90); //坐标刻度文字显示角度 curveChart->addAxis(axisX,Qt::AlignBottom); xGuideSeries->attachAxis(axisX); yGuideSeries->attachAxis(axisX); fitPointsSeriesS->attachAxis(axisX); tipSeries->attachAxis(axisX); QValueAxis* axisY = new QValueAxis; axisY->setRange(0, 500); axisY->setTickCount(11); axisY->setLabelFormat("%d"); curveChart->addAxis(axisY,Qt::AlignLeft); xGuideSeries->attachAxis(axisY); yGuideSeries->attachAxis(axisY); fitPointsSeriesS->attachAxis(axisY); tipSeries->attachAxis(axisY);// axisX->setGridLineVisible(false); //隐藏背景网格X轴框线// axisY->setGridLineVisible(false); //隐藏背景网格Y轴框线 curveChart->legend()->markers()[0]->setVisible(false); curveChart->legend()->markers()[1]->setVisible(false); curveChart->legend()->markers()[2]->setVisible(false); curveChart->legend()->markers()[3]->setVisible(false); curveChartView->setRenderHint(QPainter::Antialiasing); //除锯齿 connect(curveChartView, &FitCurveChartView::signalMouseEvent, this, &FitCurveDialog::theSlotMouseEvent); connect(curveChartView, &FitCurveChartView::signalWheelEvent, this, &FitCurveDialog::theSlotWheelEvent); ui->chartLayout->addWidget(curveChartView);}void FitCurveDialog::theSlotMouseEvent(int eventId, QMouseEvent *event) { if (eventId == 0){ //单击按下 isPressed = true; QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); pressedPoint = mouseEvent->pos(); } else if (eventId == 1) { //鼠标移动 if (isPressed) { QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); curveChart->scroll(-(mouseEvent->pos().x() - pressedPoint.x()) / 10, (mouseEvent->pos().y() - pressedPoint.y()) / 10); updateXYGuideLine(); } } else if (eventId == 2) { //单击抬起 isPressed = false; } else if (eventId == 3) { //双击 resetZoomAndScroll(); updateXYGuideLine(); }}void FitCurveDialog::theSlotWheelEvent(QWheelEvent *event) { int delta = event->angleDelta().y(); if (delta > 0) { curveChart->zoom(0.95); } else { curveChart->zoom(1.05); } updateXYGuideLine();}void FitCurveDialog::updateXYGuideLine() { if (tipSeries->points().size() > 0) { QVector<int> axisRanges = getAxisRanges(); QVector<QPointF> xGuideList, yGuideList; int tempX = tipSeries->points()[0].x(); int tempY = tipSeries->points()[0].y(); xGuideList.append(QPointF(tempX, axisRanges[2])); xGuideList.append(QPointF(tempX, tempY)); yGuideList.append(QPointF(axisRanges[0], tempY)); yGuideList.append(QPointF(tempX, tempY)); xGuideSeries->replace(xGuideList); yGuideSeries->replace(yGuideList); }}void FitCurveDialog::resetZoomAndScroll() { curveChart->zoomReset(); QList<QAbstractAxis*> axesX, axesY; axesX = curveChart->axes(Qt::Horizontal); axesY = curveChart->axes(Qt::Vertical); QValueAxis *curAxisX = (QValueAxis*)axesX[0]; QValueAxis *curAxisY = (QValueAxis*)axesY[0]; curAxisX->setRange(0, 20000); curAxisY->setRange(0, 500);}QVector<int> FitCurveDialog::getAxisRanges() { QList<QAbstractAxis*> axesX, axesY; axesX = curveChart->axes(Qt::Horizontal); axesY = curveChart->axes(Qt::Vertical); QValueAxis *curAxisX = (QValueAxis*)axesX[0]; QValueAxis *curAxisY = (QValueAxis*)axesY[0]; QVector<int> ranges = {int(curAxisX->min()), int(curAxisX->max()), int(curAxisY->min()), int(curAxisY->max())}; return ranges;}FitCurveDialog::~FitCurveDialog(){ delete ui;}