《QT实用小工具·五十》动态增删数据与平滑缩放移动的折线图

1、概述
源码放在文章末尾

该项目实现了带动画、带交互的折线图,包含如下特点:
动态增删数值
自适应显示坐标轴数值
鼠标悬浮显示十字对准线
鼠标靠近点自动贴附
支持直线与平滑曲线效果
自定义点的显示类型与大小
自适应点的数值显示位置
根据指定锚点缩放
平滑的横向移动
选中的纵向渐变效果

项目demo演示如下所示:
在这里插入图片描述

项目部分代码如下所示:

#ifndef LINECHART_H
#define LINECHART_H

#include <QObject>
#include <QWidget>
#include <QList>
#include <QPainter>
#include <QPainterPath>
#include <QPropertyAnimation>
#include <QtMath>

struct ChartData
{
    QString title;
    QColor color = Qt::black;
    int xMin = 0;
    int xMax = 0;
    int yMin = 0;
    int yMax = 0;
    QList<QPoint> points;
    QList<QString> xLabels; // X显示的名字,可空,比如日期
};

struct Vector2D : public QPointF
{
    Vector2D(double x, double y) : QPointF(x, y)
    {
    }

    Vector2D(QPointF p) : QPointF(p)
    {
    }

    /// 向量长度
    double length()
    {
        return sqrt(x() * x() + y() * y());
    }

    /// 转单位向量
    Vector2D normalize()
    {
        double len = length();
        double inv;
        if (len < 1e-4)
            inv = 0;
        else
            inv = 1 / length();
        return Vector2D(x() * inv, y() * inv);
    }

    /// 向量相加
    Vector2D operator+ (Vector2D v)
    {
        return Vector2D(x() + v.x(), y() + v.y());
    }

    /// 向量翻倍
    Vector2D operator* (double f)
    {
        return Vector2D(x() * f, y() * f);
    }

    /// 内积
    double dot(Vector2D v)
    {
        return x() * v.x() + y() * v.y();
    }

    /// 两个向量夹角
    double angle(Vector2D v)
    {
        return acos(dot(v) / (length() * v.length())) * 180 / M_PI;
    }
};

class LineChart : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(int display_x_min READ getDisplayXMin WRITE setDisplayXMin)
    Q_PROPERTY(int display_x_max READ getDisplayXMax WRITE setDisplayXMax)
    Q_PROPERTY(int display_y_min READ getDisplayYMin WRITE setDisplayYMin)
    Q_PROPERTY(int display_y_max READ getDisplayYMax WRITE setDisplayYMax)

public:
    LineChart(QWidget *parent = nullptr);

    int lineCount() const;
    void setPointLineType(int t);
    void setPointValueType(int t);
    void setPointDotType(int t);
    void setPointDotRadius(int r);
    void setLabelSpacing(int s);

    void addLine(ChartData data);
    void removeLine(int index);
    void addPoint(int index, int x, int y);
    void addPoint(int index, int x, int y, const QString& label);
    void removeFirst(int index);

    void updateAnchors();
    void zoom(double prop);
    void moveHorizontal(int x);

signals:
    void signalSelectRangeChanged(int start, int end);

public slots:
    void zoomIn();
    void zoomOut();

protected:
    void paintEvent(QPaintEvent *event) override;
    void enterEvent(QEvent *event) override;
    void leaveEvent(QEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void wheelEvent(QWheelEvent *event) override;

private:
    void setDisplayXMin(int v);
    int getDisplayXMin() const;
    void setDisplayXMax(int v);
    int getDisplayXMax() const;
    void setDisplayYMin(int v);
    int getDisplayYMin() const;
    void setDisplayYMax(int v);
    int getDisplayYMax() const;

    void saveRange();
    void startRangeAnimation();
    QPropertyAnimation* startAnimation(const QByteArray &property, int start, int end, bool* flag, int duration = 300, QEasingCurve curve = QEasingCurve::OutQuad);

    int getValueByCursorPos(QPoint pos);

private:
    // 数据
    QList<ChartData> datas;                 // 所有折线的数据

    // 界面
    QRect contentRect;                      // 显示的范围,实时刷新
    QRect paddings = QRect(32, 32, 32, 32); // 四周留白(width=right,height=bottom)
    QColor borderColor = Qt::gray;          // 边界线颜色
    int labelSpacing = 2;                   // 标签间距

    // 信息显示
    bool autoResize = true;                 // 自动调整大小
    int displayXMin = 0, displayXMax = 0;   // 显示的X轴范围
    int displayYMin = 0, displayYMax = 0;   // 显示的Y轴范围
    bool usePointXLabels = true;            // 优先使用点对应的label,还是相同间距的数值
    QList<QString> xLabels;                 // 显示的文字(可能少于值数量)
    QList<int> xLabelPoss;
    int pointLineType = 3;                  // 连线类型:1直线,2二次贝塞尔曲线,3三次贝塞尔曲线(更精确但吃性能)
    int pointValueType = 2;                 // 数值显示位置:0无,1强制上方,2自动附近
    int pointDotType = 1;                   // 圆点类型:0无,1空心圆,2实心圆,3小方块
    int pointDotRadius = 2;                 // 圆点半径

    // 动画效果
    bool enableAnimation = true;
    int _savedXMin, _savedXMax;             // 修改前的数值
    int _savedYMin, _savedYMax;
    bool animatingXMin = false, animatingXMax = false; // 是否正在动画中
    bool animatingYMin = false, animatingYMax = false;
    int _animatedXMin, _animatedXMax;       // 动画中的数值(仅影响显示)
    int _animatedYMin, _animatedYMax;

    // 交互数据
    bool pressing = false;
    QPoint pressPos, releasePos;
    bool hovering = false;
    QPoint hoverPos;
    int nearDis = 8;                        // 四周这些距离内算是“附近”

    // 悬浮提示
    bool showCrossOnPressing = true;        // 按下显示十字对准线
    QColor hightlightColor = QColor("#FF7300");       // 高亮颜色

    // 鼠标选择
    bool enableSelect = true;
    bool selecting = false;
    int selectPos = 0;                      // 最后一次鼠标点击的X像素(相对显示矩形)
    int selectXStart = 0, selectXEnd = 0;   // 鼠标按下/松开的对应X值位置
    QColor selectColor = QColor("#F08080"); // 选择区域颜色

    // 缩放(仅针对X轴)
    bool enableScale = true;
    int displayXStart = 0, displayXEnd = 0;
};

#endif // LINECHART_H

源码下载

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

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

相关文章

java并发编程-AQS介绍及源码详解

介绍 AQS 的全称为 AbstractQueuedSynchronizer &#xff0c;就是抽象队列同步器。 从源码上可以看到AQS 就是一个抽象类&#xff0c;它继承了AbstractOwnableSynchronizer&#xff0c;实现了java.io.Serializable接口。 public abstract class AbstractQueuedSynchronizere…

redis缓存详情

redis安装包及图形化软件: 百度链接&#xff1a;https://pan.baidu.com/s/1wljo7JzgrSQyqldv9d5HZA?pwdht1m 提取码&#xff1a;ht1m 目录 1.redis的下载及安装 1.1redis的启动与停止 1.2Redis服务启动与停止 2.redis数据类型及常用指令 2.1redis数据类型 2.2redis常用…

读天才与算法:人脑与AI的数学思维笔记15_声响的数学之旅

1. 音乐 1.1. 巴赫的作品以严格的对位著称&#xff0c;他十分中意对称的结构 1.2. 巴托克的作品很多都以黄金比例为结构基础&#xff0c;他非常喜欢并善于使用斐波纳契数列 1.3. 有时&#xff0c;作曲家是本能地或者不自知地被数学的模式和结构所吸引&#xff0c;而他们并没…

Golang | Leetcode Golang题解之第61题旋转链表

题目&#xff1a; 题解&#xff1a; func rotateRight(head *ListNode, k int) *ListNode {if k 0 || head nil || head.Next nil {return head}n : 1iter : headfor iter.Next ! nil {iter iter.Nextn}add : n - k%nif add n {return head}iter.Next headfor add > …

【项目构建】04:动态库与静态库制作

OVERVIEW 1.编译动态链接库&#xff08;1&#xff09;编译动态库&#xff08;2&#xff09;链接动态库&#xff08;3&#xff09;运行时使用动态库 2.编译静态链接库&#xff08;1&#xff09;编译静态库&#xff08;2&#xff09;链接静态库&#xff08;3&#xff09;运行时使…

matlab学习007-已知离散时间系统的系统函数并使用matlab绘制该系统的零极点图;判断系统的稳定性;幅频和相频特性曲线

目录 题目 离散时间系统的系统函数&#xff1a;H(z)(3*z^3-5*z^210z)/(z^3-3*z^27*z-5) 1&#xff0c;绘制该系统的零极点图 1&#xff09;零极点图 2&#xff09;代码 2&#xff0c;判断系统的稳定性 1&#xff09;判断结果 2&#xff09;代码 3&#xff0c;试用MATL…

C++的未来之路:探索与突破

在计算机科学的浩瀚星空中&#xff0c;C无疑是一颗璀璨的明星。自诞生以来&#xff0c;它以其强大的性能和灵活的特性&#xff0c;赢得了无数开发者的青睐。然而&#xff0c;随着技术的不断进步和应用的日益复杂&#xff0c;C也面临着前所未有的挑战和机遇。本文将探讨C的未来之…

腾锐D2000-8 MXM VPX,全国产,可广泛应用于边缘计算网关、入侵检测、VPN、网络监控等等应用领域

腾锐D2000-8 MXM VPX 1. 概述 XMVPX-108 是一款基于飞腾 D2000/8 处理器的低功耗逻辑运算和图形处理 VPX 刀片&#xff0c; 板贴 32GB DDR4 内存&#xff0c;搭载飞腾 X100 套片&#xff0c;满足通用 IO 接口功能。GPU 采用 MXM 小型插卡形式&#xff0c; 搭配 8GB 显卡。提供…

【16-降维技术:PCA与LDA在Scikit-learn中的应用】

文章目录 前言主成分分析(PCA)原理简介Scikit-learn中的PCA实现应用示例线性判别分析(LDA)原理简介Scikit-learn中的LDA实现应用示例总结前言 降维是机器学习中一种常见的数据预处理方法,旨在减少数据集的特征数量,同时尽量保留原始数据集的重要信息。这不仅有助于减少计…

开箱子咸鱼之王H5游戏源码_内购修复优化_附带APK完美运营无bug最终版__GM总运营后台_附带安卓版本

内容目录 一、详细介绍二、效果展示2.效果图展示 三、学习资料下载 一、详细介绍 1.包括原生打包APK&#xff0c;资源全部APK本地化&#xff0c;基本上不跑服务器宽带 2.优化后端&#xff0c;基本上不再一直跑内存&#xff0c;不炸服响应快&#xff01; 3.优化前端&#xff0c…

【源码阅读】Golang中的go-sql-driver库源码探究

文章目录 前言一、go-sql-driver/mysql1、驱动注册&#xff1a;sql.Register2、驱动实现&#xff1a;MysqlDriver3、RegisterDialContext 二、总结 前言 在上篇文章中我们知道&#xff0c;database/sql只是提供了驱动相关的接口&#xff0c;并没有相关的具体实现&#xff0c;具…

NLP 笔记:TF-IDF

TF-IDF&#xff08;Term Frequency-Inverse Document Frequency&#xff0c;词频-逆文档频率&#xff09;是一种用于信息检索和文本挖掘的统计方法&#xff0c;用来评估一个词在一组文档中的重要性。TF-IDF的基本思想是&#xff0c;如果某个词在一篇文档中出现频率高&#xff0…

不坑盒子2024.0501版,Word朗读、Word表格计算、Word中代码高亮显示行号、Excel中正则提取内容……

通过“听”来审阅Word中的内容&#xff0c;能轻松找出那些容易被眼看忽视的错字。 不坑盒子2024.0501版来了&#xff0c;很多奇妙的事情&#xff0c;正在发生…… 功能一览 此版本共带来10余项变动&#xff0c;来看看有没有你感兴趣的吧~ 接入Azure的“语音”能力 接入“语…

Flutter笔记:Widgets Easier组件库(3)使用按钮组件

Flutter笔记 Widgets Easier组件库&#xff08;3&#xff09;&#xff1a;使用按钮组件 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddre…

C语言之详细讲解文件操作(抓住文件操作的奥秘)

什么是文件 与普通文件载体不同&#xff0c;文件是以硬盘为载体存储在计算机上的信息集合&#xff0c;文件可以是文本文档、图片、程序等等。文件通常具有点三个字母的文件扩展名&#xff0c;用于指示文件类型&#xff08;例如&#xff0c;图片文件常常以KPEG格式保存并且文件…

JDBC连接MySQL8 SSL

1.创建用户并指定ssl连接 grant all on . to test% identified by imooc require SSL(X509); 2.查看是否使用ssl SELECT ssl_type From mysql.user Where user"test" 3.配置用户必须使用ssl ALTER USER test% REQUIRE SSL(X509); FLUSH PRIVILEGES; 注意&#xff…

Ollamallama

Olllama 直接下载ollama程序&#xff0c;安装后可在cmd里直接运行大模型&#xff1b; llama 3 meta 开源的最新llama大模型&#xff1b; 下载运行 1 ollama ollama run llama3 2 github 下载仓库&#xff0c;需要linux环境&#xff0c;windows可使用wsl&#xff1b; 接…

mac如何打开exe文件?如何mac运行exe文件 如何在Mac上打开/修复/恢复DMG文件

在macOS系统中&#xff0c;无法直接运行Windows系统中的.exe文件&#xff0c;因为macOS和Windows使用的是不同的操作系统。然而&#xff0c;有时我们仍然需要运行.exe文件&#xff0c;比如某些软件只有Windows版本&#xff0c;或者我们需要在macOS系统中运行Windows程序。 虽然…

【MATLAB源码-第200期】基于matlab的鸡群优化算法(CSO)机器人栅格路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 鸡群优化算法&#xff08;Chicken Swarm Optimization&#xff0c;简称CSO&#xff09;是一种启发式搜索算法&#xff0c;它的设计灵感来源于鸡群的社会行为。这种算法由Xian-bing Meng等人于2014年提出&#xff0c;旨在解决…

STM32 工程移植 LVGL:一步一步完成

STM32 工程移植 LVGL&#xff1a;一步一步完成 LVGL&#xff0c;作为一款强大且灵活的开源图形库&#xff0c;专为嵌入式系统GUI设计而生&#xff0c;极大地简化了开发者在创建美观用户界面时的工作。作为一名初学者&#xff0c;小编正逐步深入探索LVGL的奥秘&#xff0c;并决…
最新文章