话不多说。

第一步:自定义QChartView,直接搬

FirtCurveChartView.h

#ifndef FITCURVECHARTVIEW_H
#define FITCURVECHARTVIEW_H
#include <QtCharts>

class FitCurveChartView : public QChartView {
    Q_OBJECT

public:
    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_OBJECT

public:
    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;
}

效果:(动图依次展示:①点击曲线显示坐标->②平移->③缩放->④双击还原)

Qt篇——QChartView实现鼠标滚轮缩放、鼠标拖拽平移、鼠标双击重置缩放平移、曲线点击显示坐标-LMLPHP

12-07 10:44