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

话不多说。

第一步:自定义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;
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/218995.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

23、什么是卷积的 Feature Map?

这一节介绍一个概念&#xff0c;什么是卷积的 Feature Map&#xff1f; Feature Map, 中文称为特征图&#xff0c;卷积的 Feature Map 指的是在卷积神经网络&#xff08;CNN&#xff09;中&#xff0c;通过卷积这一操作从输入图像中提取的特征图。 上一节用示意动图介绍了卷积算…

【开源】基于Vue和SpringBoot的开放实验室管理系统

项目编号&#xff1a; S 013 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S013&#xff0c;文末获取源码。} 项目编号&#xff1a;S013&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实…

3.镜像加速器

目录 1 阿里云 2 网易云 从网络上拉取镜像的时候使用默认的源可能会慢&#xff0c;用国内的源会快一些 1 阿里云 访问 阿里云-计算&#xff0c;为了无法计算的价值 然后登录&#xff0c;登录后搜索 容器镜像服务 点击容器镜像服务 点击管理控制台 点击 镜像工具->镜像…

Python的requests库实现HTTPS

嘿&#xff0c;Python程序员们&#xff01;今天我们要来点刺激的——使用Python的requests库实现HTTPS请求&#xff01;是的&#xff0c;你没有听错&#xff0c;我们要一起迈入HTTPS的神秘世界&#xff01; 首先&#xff0c;我们来了解一下HTTPS是什么。HTTPS是HTTP Secure的缩…

前端时间的失败总结复盘

分享失败经验&#xff0c;前段时间的总结复盘&#xff1a; 与伙伴合作面对异常决策要及时提出质疑&#xff0c;怼&#xff0c;别太客气&#xff0c;客气起来&#xff0c;小心翼翼在意他人情绪那么这个项目就会让人难受&#xff0c;不要因为因为伙伴身上有标签/光环/权威就觉得…

【C++】map和set的使用及注意事项

map和set的使用及注意事项 1.关联式容器2. 键值对3.set3.1接口介绍3.1.1构造3.1.2迭代器3.1.3容量3.1.4修改 3.2set使用及注意事项 4.multiset5.map6.multimap349. 两个数组的交集 1.关联式容器 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比如&#xf…

持续集成交付CICD:Sonarqube 扫描本地项目(关联Gitlab项目与Jenkins流水线)

目录 一、实验 1.Java项目扫描 2.视图徽章 3.版本管理 一、实验 1.Java项目扫描 &#xff08;1&#xff09;指定项目信息关联的首页为GitLab项目&#xff0c;持续集成为Jenkins流水线 &#xff08;2&#xff09;命令行 sonar-scanner -Dsonar.host.urlhttp://192.168.20…

RAG落地实践、AI游戏开发、上海·深圳·广州线下工坊启动!星河社区重磅周

飞桨星河社区在成立的5年以来&#xff0c;已汇集660万AI开发者&#xff0c;覆盖深度学习初学者、在职开发者、企业开发者、高校教师、创业者等&#xff0c;已成为AI领域最具影响力的社区之一&#xff0c;无论是AI爱好者还是AI开发者&#xff0c;都能在这里探索AI的无限可能。 飞…

字符指针变量数组指针变量

字符指针变量 在指针的类型中&#xff0c;我们知道有一种指针叫做字符指针 一般的使用情况如下&#xff1a; #include<stdio.h> int main() {char ch w;char* pa &ch;*pa h;printf("%c", *pa);return 0; } 还有一种使用方法如下&#xff1a; #incl…

计算机速成课Crash Course - 07. 中央处理器

今天开始计算机速成课Crash Course的系列讲解。 更多技术文章&#xff0c;全网首发公众号 “摸鱼IT” 锁定 -上午11点 - &#xff0c;感谢大家关注、转发、点赞&#xff01; 计算机速成课Crash Course - 07. 中央处理器 07. 中央处理器 提示下&#xff0c;这集可能是最难的一…

Python-图片去重

直接上代码 # 修改一下第34行文件夹路径以及13行图片后缀名即可使用 import os from hashlib import md5def remove_duplicate_images(folder_path):image_files []duplicate_images set()# 遍历文件夹&#xff0c;找到所有 JPG 图片文件for root, dirs, files in os.walk(f…

LeetCode | 110. 平衡二叉树

LeetCode | 110. 平衡二叉树 OJ链接 首先计算出二叉树的高度然后计算当前节点的左右子树的高度&#xff0c;然后判断当前节点的左右子树高度差是否超过 1&#xff0c;最后递归地检查左右子树是否也是平衡的。 //计算二叉树的高度 int height(struct TreeNode* root) {if(root…

SOLIDWORKS弯曲特征在泵阀行业中的应用

弯曲特征-折弯 此类弯曲特征以绕三重轴的折弯轴折弯一个或多个实体。 定位三重轴和剪裁基准面&#xff0c;控制折弯的角度、位置和界限。 此弯曲类型可用于多种应用&#xff0c;包括工业设计、机械设计、解决金属冲压中的回弹条件以及从复杂的曲面形状中删除底切等。 本篇文章…

【每日易题】Leetcode上Hard难度的动态规划题目——地下城游戏的实现

君兮_的个人主页 即使走的再远&#xff0c;也勿忘启程时的初心 C/C 游戏开发 Hello,米娜桑们&#xff0c;这里是君兮_&#xff0c;博主最近一直在钻研动态规划算法&#xff0c;最近在Leetcode上刷题的时候遇到一个Hard难度的动态规划题&#xff0c;今天就借此机会来给大家分享…

CopyOnWriteArrayList怎么用

什么是CopyOnWriteArrayListCopyOnWriteArrayList常用方法CopyOnWriteArrayList源码详解CopyOnWriteArrayList使用注意点CopyOnWriteArrayList存在的性能问题CopyOnWriteArrayList 使用实例基本应用实例并发应用实例 拓展写时复制 什么是CopyOnWriteArrayList CopyOnWriteArra…

Uber Go 语言编码规范

uber-go/guide 的中文翻译 English 文档链接 Uber Go 语言编码规范 Uber 是一家美国硅谷的科技公司&#xff0c;也是 Go 语言的早期 adopter。其开源了很多 golang 项目&#xff0c;诸如被 Gopher 圈熟知的 zap、jaeger 等。2018 年年末 Uber 将内部的 Go 风格规范 开源到 G…

每天一点python——day85

#每天一点Python——85 #python常见的异常类型&#xff1a; #如图&#xff1a; #①数学运算异常【由于会报错&#xff0c;我直接全部注释掉了】 print(10/0) 输出&#xff1a;ZeroDivisionError: division by zero#②索引错误list1[1,2,3,4] print(list1[5])#找索引为4的元素 输…

谈一谈内存池

文章目录 一&#xff0c;什么是内存池二&#xff0c;进程地址空间中是如何解决内存碎片问题的三&#xff0c;malloc的实现原理四&#xff0c;STL中空间配置器的实现原理五&#xff0c;高并发内存池该内存池的优势在哪里内存池的设计框架内存申请流程ThreadCache层CentreCache层…

优酷新国风动漫《师兄啊师兄 第二季》强势定档 看李长寿稳健归来!

看新国风&#xff0c;上优酷动漫&#xff01;由优酷出品&#xff0c;玄机科技制作&#xff0c;改编自阅文集团旗下起点读书小说《我师兄实在太稳健了》&#xff08;作者&#xff1a;言归正传&#xff09;的修仙喜剧动画《师兄啊师兄》第二季《海神扬名篇》今日正式官宣定档&…

【Docker】从零开始:13.Docker安装tomcat

Docker】从零开始&#xff1a;13.Docker安装Tomcat 下载Tomcat镜像启动Tomcat镜像新版本Tomcat修改访问Tomact首页 下载Tomcat镜像 [rootdocker ~]# docker pull tomcat Using default tag: latest latest: Pulling from library/tomcat 0e29546d541c: Pull complete 9b829c7…