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

news2024/9/24 9:26:04

话不多说。

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

apk反编译修改教程系列---简单去除apk开屏广告【五】

往期教程&#xff1a; apk反编译修改教程系列-----修改apk应用名称 任意修改名称 签名【一】 apk反编译修改教程系列-----任意修改apk版本号 版本名 防止自动更新【二】 apk反编译修改教程系列-----修改apk中的图片 任意更换apk桌面图片【三】 apk反编译修改教程系列---简单…

算法学习—排序

排序算法 一、选择排序 1.算法简介 选择排序是一个简单直观的排序方法&#xff0c;它的工作原理很简单&#xff0c;首先从未排序序列中找到最大的元素&#xff0c;放到已排序序列的末尾&#xff0c;重复上述步骤&#xff0c;直到所有元素排序完毕。 2.算法描述 1&#xff…

Linux中项目部署步骤

安装jdk&#xff0c;tomcat 安装步骤 1&#xff0c;将压缩包&#xff0c;拷贝到虚拟机中。 通过工具&#xff0c;将文件直接拖到虚拟机的/home下 2&#xff0c;回到虚拟机中&#xff0c;查看/home下&#xff0c;有两个压缩文件 3&#xff0c;给压缩文件做解压缩操作 tar -z…

分享70个节日PPT,总有一款适合您

分享70个节日PPT&#xff0c;总有一款适合您 70个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/1IRIKuFoGjQJ14OVkeW_mDQ?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…

Nuxt3 使用 pinia 基础

官方文档 一、安装 pnpm add pinia/nuxt二、配置 添加到 nuxt.config.js 中的 modules &#xff08;Nuxt 3&#xff09;或 buildModules &#xff08;Nuxt 2&#xff09;&#xff1a; // Nuxt 2 export default {buildModules: [[pinia/nuxt, { disableVuex: true }]], } /…

MySQL-含json字段表和与不含json字段表查询性能对比

含json字段表和与不含json字段表查询性能对比 说明: EP_USER_PICTURE_INFO_2:不含json字段表 20200729json_test:含有json字段表 其中20200729json_test 标准ID、MANAGER_NO、PHONE_NO 为非json字段 data为json字段 2个表中MANAGER_NO、PHONE_NO都创建了各自的索引 测试…

拼多多电商平台API接口,获取拼多多实时准确数据,获取产品销量、价格,sku图片及sku库存数据演示

拼多多商品详情API接口的作用是让开发者可以获取拼多多平台上特定商品的详细信息&#xff0c;包括商品的标题、价格、图片、规格、参数以及店铺信息等。通过这个接口&#xff0c;开发者可以轻松地获取商品的原始数据&#xff0c;便于进行数据分析、价格比较、爬取等操作。这为电…

python和php语言编写大型爬虫那个更适用 ?

以我多年从事爬虫行业的经验来说&#xff0c;其实python和php两种语言都可以用于编写大型爬虫项目&#xff0c;但是因为Python语言简洁方便&#xff0c;第三方库相比有很多&#xff0c;数据处理能力也很强&#xff0c;所以受到大多数程序员的追捧。 Python和PHP都可以用于编写…

32位旧内核2038溢出time记录

项目中有使用arm32的机器 现在内核动不了 有个使用时间范围显示是2023-2123 int在32bit下的 2038危机诞生了。 下面在svn找到代码 优化了一下 供大家学习哈&#xff0c;废话不多说直接上家伙&#xff1a; 需要的函数自己抄 #pragma once #include <stdio.h> #include …

Java 并发编程面试题——Java 线程间通信方式

目录 1.✨Java 线程间有哪些通信方式&#xff1f;1.1.volatile 和 synchronized 关键字1.2.等待/通知机制1.2.1.概述1.2.2.经典范式 1.3.管道输入/输出流1.4.信号量 2.Thread.join() 有什么作用&#xff1f;它的使用场景是什么&#xff1f;3.Java 中需要主线程等待子线程执行完…

家用打印机品牌多,种类杂,那么如何挑选最适合的家用打印机

在购买最好的家用打印机时&#xff0c;你可能会寻找足够多功能的打印机来满足每个人的需求。你的家人可能需要复印文件签字&#xff0c;扫描精致的旧照片&#xff0c;或者在接到通知后立即打印长篇文章或报告。良好的扫描功能确保你可以快速高效地将工作数字化&#xff0c;而每…

工程化使用React

安装 首先全局安装 npm install create-react-app -g创建项目 create-react-app proName最基本的一个react工程化创建完成 项目目录

CRM:如何通过客户数据分析获得业务洞察?

客户数据分析&#xff0c;也称客户分析&#xff0c;是收集、组织和分析客户数据&#xff0c;以深入了解客户行为的过程。企业将利用这些数据来制定与营销、产品开发、销售等相关的业务决策。 通过客户分析&#xff0c;你可以做出简单的业务决策&#xff0c;比如找出投资回报率…

基于PaddleSeg开发的人像抠图web api接口

前言 基于PaddleSeg开发的人像抠图web api接口&#xff0c;提取官方代码&#xff0c;适配各种系统&#xff0c;通过api的接口进行访问。 环境要求 1、Python3.7以上 2、源码&#xff08;文章最后下载&#xff09; 源码结构 测试module.py中添加如下代码&#xff1a; if __na…

城市内涝监测如何防治

洪涝灾害是我国历史上主要自然灾害之一&#xff0c;由于我国大部分地区受季风气候影响和降水季节性分配和空间分布不平衡等因素&#xff0c;一些城市洪涝灾害易发多发&#xff0c;危及城市居民的生命财产安全&#xff0c;也影响城市安全运行和可持续发展。因此&#xff0c;城市…

SQL Sever 基础知识 - 数据筛选(1)

SQL Sever 基础知识 - 四、数据筛选 四、筛选数据第1节 DISTINCT - 去除重复值1.1 SELECT DISTINCT 子句简介1.2 SELECT DISTINCT 示例1.2.1 DISTINCT 一列示例1.2.2 DISTINCT 多列示例 1.2.3 DISTINCT 具有 null 值示例1.2.4 DISTINCT 与 GROUP BY 对比 第2节 WHERE - 过滤查询…

easyexcel的@NumberFormat源码解析

debug了一天&#xff0c;关键源码如下&#xff1a; com.alibaba.excel.write.executor.AbstractExcelWriteExecutor#converterAndSet 由于 NumberFormat 注解对应的字段肯定是 BigDecimal &#xff0c;所以肯定会走这一步 然后进行赋值&#xff0c;然后再之前给cell设置好了格…

linux部署前端页面(实战)

Linux基本命令&#xff08;学习笔记&#xff09;零基础入门linux系统运维_linux find exec rm_Z_Xshan的博客-CSDN博客 如果linux不熟可以看我之前写的入门教程 感谢支持&#xff01;&#xff01; 一、服务器 这里去购买云服务器&#xff0c;如果是练习可以用虚拟机&#xff…

Sequential Modeling Enables Scalable Learning for Large Vision Models

目录 一、论文速读 1.1 摘要 1.2 论文概要总结 二、论文精度 2.1 论文试图解决什么问题&#xff1f; 2.2 论文中提到的解决方案之关键是什么&#xff1f; 2.3 论文提出的架构和损失函数是什么&#xff1f; 2.4 用于定量评估的数据集是什么&#xff1f;代码有没有开源&a…