当前位置: 首页 > news >正文

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

话不多说。

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

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

相关文章:

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

话不多说。 第一步&#xff1a;自定义QChartView&#xff0c;直接搬 FirtCurveChartView.h #ifndef FITCURVECHARTVIEW_H #define FITCURVECHARTVIEW_H #include <QtCharts>class FitCurveChartView : public QChartView {Q_OBJECTpublic:FitCurveChartView(QWidget *…...

掌握VUE中localStorage的使用

文章目录 &#x1f341;localStorage的使用&#x1f33f;设置数据&#x1f33f;获取数据&#x1f33f;更新数据&#x1f33f;删除数据 &#x1f341;代码示例&#x1f341;使用场景&#x1f341;总结 localStorage是一种Web浏览器提供的本地存储机制&#xff0c;允许开发者在用…...

所有行业的最终归宿-我有才打造知识付费平台

随着科技的不断进步和全球化的加速发展&#xff0c;我们生活在一个信息爆炸的时代。各行各业都在努力适应这一变化&#xff0c;寻找新的商业模式和增长机会。在这个过程中&#xff0c;一个趋势逐渐凸显出来&#xff0c;那就是知识付费。可以说&#xff0c;知识付费正在成为所有…...

图的深度和广度优先遍历

题目描述 以邻接矩阵给出一张以整数编号为顶点的图&#xff0c;其中0表示不相连&#xff0c;1表示相连。按深度和广度优先进行遍历&#xff0c;输出全部结果。要求&#xff0c;遍历时优先较小的顶点。如&#xff0c;若顶点0与顶点2&#xff0c;顶点3&#xff0c;顶点4相连&…...

计算机毕业设计JAVA+SSM+springboot养老院管理系统

设计了养老院管理系统&#xff0c;该系统包括管理员&#xff0c;医护人员和老人三部分。同时还能为用户提供一个方便实用的养老院管理系统&#xff0c;管理员在使用本系统时&#xff0c;可以通过系统管理员界面管理用户的信息&#xff0c;也可以进行个人中心&#xff0c;医护等…...

Flutter路由的几种用法

Flutter路由跳转 基本路由跳转 ElevatedButton(onPressed: () {//基本路由跳转Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) {return const SearchPage();}),);},child: const Text("基本路由跳转"), ), search.dart页面 impo…...

力扣119双周赛

第 119 场双周赛 文章目录 第 119 场双周赛找到两个数组中的公共元素消除相邻近似相等字符最多 K 个重复元素的最长子数组找到最大非递减数组的长度 找到两个数组中的公共元素 模拟 class Solution { public:vector<int> findIntersectionValues(vector<int>&…...

Redux,react-redux,dva,RTK

1.redux的介绍 Redux – 李立超 | lilichao.com 2.react-redux 1&#xff09;react-Redux将所有组件分成两大类 UI组件 只负责 UI 的呈现&#xff0c;不带有任何业务逻辑通过props接收数据(一般数据和函数)不使用任何 Redux 的 API一般保存在components文件夹下容器组件 …...

基于Java SSM框架实现高校信息资源共享平台系统【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现高校信息资源共享平台系统演示 摘要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们…...

SpringMvc入坑系列(一)----maven插件启动tomcat

springboot傻瓜式教程用久了&#xff0c;回过来研究下SSM的工作流程&#xff0c;当然从Spring MVC开始&#xff0c;从傻瓜式入门处理请求和页面交互&#xff0c;再到后面深入源码分析。 本人写了一年多的后端和半年多的前端了。用的都是springbioot和vue&#xff0c;源码一直来…...

Leetcode—337.打家劫舍III【中等】

2023每日刷题&#xff08;五十二&#xff09; Leetcode—337.打家劫舍III 算法思想 实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(null…...

列表标签的介绍与使用

列表的作用&#xff1a; 整齐、整洁、有序&#xff0c;它作为布局会更加自由和方便。 根据使用情景不同&#xff0c;列表可以分为三大类&#xff1a;无序列表、有序列表和自定义列表 无序列表 <ul> 标签表示 HTML 页面中项目的无序列表&#xff0c;一般会以项目符号呈…...

浅谈什么是语音芯片的白噪音支持功能:打造舒适家居与优质音频体验

随着科技的不断进步和人们对生活质量要求的提升&#xff0c;语音芯片已经成为了现代电子产品中不可或缺的一部分。而在这些语音芯片中&#xff0c;支持白噪音的功能逐渐受到人们的关注。本文将围绕语音芯片中的白噪音支持功能展开讨论&#xff0c;带您领略其带来的舒适家居与优…...

【QED】高昂的猫 Ⅰ

目录 题目背景题目描述输入格式输出格式 测试样例样例说明数据范围 思路核心代码 题目背景 这是小橘。因为它总是看起来很高傲&#xff0c;所以人送外号“高昂的猫”。 题目描述 "锕狗"的房间里放着 n n n ( 1 ≤ n ≤ 1 0 9 ) (1 \leq n \leq 10^9) (1≤n≤109)个…...

Redis如何做内存优化?

Redis如何做内存优化&#xff1f; 1、缩短键值的长度 缩短值的长度才是关键&#xff0c;如果值是一个大的业务对象&#xff0c;可以将对象序列化成二进制数组&#xff1b; 首先应该在业务上进行精简&#xff0c;去掉不必要的属性&#xff0c;避免存储一些没用的数据&#xff1…...

倪海厦:教你正确煮中药,发挥最大药效

同样的一个汤剂&#xff0c;我开给你&#xff0c;你如果煮的方法不对&#xff0c;吃下去效果就没那么好。 所以&#xff0c;汤&#xff0c;取它的迅捷&#xff0c;速度很快&#xff0c;煮汤的时候还有技巧&#xff0c;你喝汤料的时候&#xff0c;你到底是喝它的气&#xff0c;…...

C++学习笔记:继承

继承 什么是继承?继承的写法基类和派生类的赋值转换继承中的作用域派生类的默认成员函数单继承,多继承,虚拟继承is-a 和 has-a 什么是继承? 继承是C语言面向对象的三大特性之一&#xff0c;是面向对象程序设计使代码可以复用的最重要的手段,基本都是在一个类的基础上为了增加…...

音频/视频、信息和通信技术设备安全标准UL62368-1

UL 62368-1&#xff0c;第 3 版&#xff0c;2019 年 12 月 13 日- UL 音频/视频、信息和通信技术设备安全标准 - 第 1 部分&#xff1a;安全要求 IEC 62368 的这一部分适用于该领域内电气和电子设备的安全音频、视频、信息和通信技术&#xff0c;以及额定电压不超过 600 V 的商…...

macos下安装科研绘图软件Origin

科研人必备软件Origin&#xff0c;主要是考虑到很多期刊都要求绘制origin可编辑的图&#xff0c;所以有些时候必须用这个软件&#xff0c;但是这个软件macos并不支持&#xff0c;所以必须考虑其他的方案&#xff0c;我没有安装虚拟机&#xff0c;而是使用crossover 安装crosso…...

安全快速地删除 MySQL 大表数据并释放空间

一、需求 按业务逻辑删除大量表数据操作不卡库&#xff0c;不能影响正常业务操作操作不能造成 60 秒以上的复制延迟满足以上条件的前提下&#xff0c;尽快删除数据并释放所占空间 表结构如下&#xff1a; create table space_visit_av (userid bigint(20) not null comment 用…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...