【QT】】qcustomplot的初步使用二

news2025/3/21 5:01:38

功能预期:

在简单显示曲线()基础上加功能:
1.在曲线区域里,X轴可以随鼠标滚轮变化将图像缩放、随鼠标左键进行曲线移动;
2.在曲线区域里,Y轴的量程可以随Y轴数据大小自适应;
3.可以动态显示最新的数据。
4.拓展:再增加一条曲线同时显示
在这里插入图片描述

代码实现

具体细节已在注释中标记清楚
mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "qcustomplot.h"  // 引入QCustomPlot头文件
#include <QWheelEvent> // 引入QWheelEvent头文件
#include <QMouseEvent>  // 引入QMouseEvent头文件
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QCustomPlot *customPlot; // 添加QCustomPlot指针
    QTimer *dataTimer; // 定时器
    QVector<double> xData, yData; // 数据存储
    void updatePlot(); // 更新图表的函数

    void wheelEvent(QWheelEvent *event) override;  // 确保加上 override
    void mousePressEvent(QMouseEvent *event) override;  // 鼠标按下事件
    void mouseMoveEvent(QMouseEvent *event) override;   // 鼠标移动事件
    void mouseReleaseEvent(QMouseEvent *event) override; // 鼠标释放事件

    bool dragging = false; // 是否正在拖动
    QPoint lastMousePos;   // 记录鼠标位置
};

#endif // MAINWINDOW_H

main.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}
void MainWindow::updatePlot()
{
    // 生成新的数据点
    static double time = 0;
    static double signalValue = 0;

    // 生成新信号值(如正弦波)
    signalValue = 65 * qSin(time);
    time += 0.1;

    // 保存数据
    xData.append(time);
    yData.append(signalValue);

    // 更新图表
    customPlot->graph(0)->setData(xData, yData);

    // 自动调整Y轴范围
    customPlot->yAxis->rescale(true);

    // 更新X轴的范围(保持当前显示区间的时间轴范围)
    double lowerX = customPlot->xAxis->range().lower;
    double upperX = customPlot->xAxis->range().upper;

    // 设置X轴范围,确保X轴根据时间区间自动调整
    if (time > upperX) {
        customPlot->xAxis->setRange(lowerX + 0.1, upperX + 0.1); // 保持动态显示10秒的数据
    }
   //刷新数据显示
    ui->Hvalue_label->setText(QString::number(signalValue));
    ui->Svalue_label->setText(QString::number(time));
    // 刷新图表

    customPlot->replot();
}
void MainWindow::wheelEvent(QWheelEvent *event)
{
    // 检查鼠标指针是否在 customPlot 区域内
    if (!customPlot->geometry().contains(event->pos())) {
        // 如果不在 customPlot 区域内,直接返回
        return;
    }
    // 获取当前X轴范围
    double currentRange = customPlot->xAxis->range().upper - customPlot->xAxis->range().lower;

    // 获取滚轮的增量
    int a = event->angleDelta().y(); // 获取滚动的垂直方向(正为向上滚动,负为向下滚动)

    // 设定缩放步长
    double zoomFactor = 0.1; // 每次滚动缩放的比例(可调整)

    if (a > 0) {
        // 向上滚动,缩小X轴范围
        customPlot->xAxis->setRange(customPlot->xAxis->range().lower + zoomFactor * currentRange,
                                    customPlot->xAxis->range().upper - zoomFactor * currentRange);
    } else {
        // 向下滚动,放大X轴范围
        customPlot->xAxis->setRange(customPlot->xAxis->range().lower - zoomFactor * currentRange,
                                    customPlot->xAxis->range().upper + zoomFactor * currentRange);
    }

    // 确保X轴的范围不小于0
    if (customPlot->xAxis->range().lower < 0) {
        customPlot->xAxis->setRange(0, customPlot->xAxis->range().upper);
    }

    // 重新绘制图表
    customPlot->replot();
}
// 鼠标按下事件
void MainWindow::mousePressEvent(QMouseEvent *event)
{
    // 检查鼠标指针是否在 customPlot 区域内
    if (!customPlot->geometry().contains(event->pos())) {
        // 如果不在 customPlot 区域内,直接返回
        return;
    }
    if (event->button() == Qt::LeftButton) {
        // 鼠标左键按下,记录鼠标当前位置
        lastMousePos = event->pos();
        dragging = true;
    }
}

// 鼠标移动事件
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if (dragging) {
        // 计算鼠标拖动的距离
        int X = event->pos().x() - lastMousePos.x();

        // 根据移动的距离调整X轴范围
      //  double currentRange = customPlot->xAxis->range().upper - customPlot->xAxis->range().lower;
        customPlot->xAxis->setRange(customPlot->xAxis->range().lower -X * 0.1, customPlot->xAxis->range().upper -X * 0.1);

        // 更新最后的鼠标位置
        lastMousePos = event->pos();

        // 重新绘制图表
        customPlot->replot();
    }
}

// 鼠标释放事件
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        dragging = false;
    }
}

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTimer>
#include <QVector>
#include <cmath> // 使用数学函数

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);// 初始化 UI
   // ui->Hvalue_label->setText(QString::number(0));  //初始化label的数据
    // 初始化QCustomPlot
   // 使用UI的customPlot名字而不是创建一个新的。
    customPlot = ui->customPlot1;

   // customPlot = new QCustomPlot(this);
   // setCentralWidget(customPlot);

    // 设置 customPlot 以便它接收焦点,确保能够处理事件
        customPlot->setFocus();
    // 确保QCustomPlot能够接收鼠标事件
           customPlot->setFocusPolicy(Qt::StrongFocus); // 设置焦点策略,确保能够接收事件
    //避免其他控件(比如按钮、标签等)覆盖在其上面,或者其他控件阻止了事件的传递
     customPlot->setAttribute(Qt::WA_TransparentForMouseEvents);
    // 配置图表
    customPlot->addGraph();
    customPlot->graph(0)->setPen(QPen(Qt::red)); // 设置曲线颜色

   // customPlot->graph(0)->setBrush(QBrush(QColor(0, 0, 255, 20))); // 曲线与X轴包围区的颜色
    //设置XY轴的名字
    customPlot->xAxis->setLabel("时间 (s)");
    customPlot->yAxis->setLabel("相对地面高度");

    // 启用自动缩放 在updatePlot中更新Y轴范围

 //   customPlot->graph(0)->rescaleAxes(true);        //打开注释将开启自适应量程功能

    //customPlot->xAxis->setRange(0, 20);
   // customPlot->yAxis->setRange(0, 120);

    // 初始化定时器
    dataTimer = new QTimer(this);
    connect(dataTimer, &QTimer::timeout, this, &MainWindow::updatePlot);
    dataTimer->start(20); // 每20毫秒更新一次

    // 初始化数据
    xData.clear();
    yData.clear();
}
MainWindow::~MainWindow()
{
    delete ui;
}



细节注意:

 // 设置 customPlot 以便它接收焦点,确保能够处理事件
    customPlot->setFocus();
// 确保QCustomPlot能够接收鼠标事件
       customPlot->setFocusPolicy(Qt::StrongFocus); // 设置焦点策略,确保能够接收事件
//避免其他控件(比如按钮、标签等)覆盖在其上面,或者其他控件阻止了事件的传递
 customPlot->setAttribute(Qt::WA_TransparentForMouseEvents);

这里主要解决:customPlot1区域里不能实现wheelEvent的函数,在其他界面的区域可以实现wheelEvent函数

// 检查鼠标指针是否在 customPlot 区域内
if (!customPlot->geometry().contains(event->pos())) {
// 如果不在 customPlot 区域内,直接返回
return;
}

这里主要解决:仅在曲线区域内生效

代码结构

在这里插入图片描述
使用环境:QT5.15.1
欢迎批评指正!

曲线

拓展

如果要再添加一条曲线

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);// 初始化 UI

    // 初始化QCustomPlot
    customPlot = ui->customPlot1; // 使用UI的customPlot名字而不是创建一个新的。

    // 设置 customPlot 以便它接收焦点,确保能够处理事件
    customPlot->setFocus();
    // 确保QCustomPlot能够接收鼠标事件
    customPlot->setFocusPolicy(Qt::StrongFocus); // 设置焦点策略,确保能够接收事件
    customPlot->setAttribute(Qt::WA_TransparentForMouseEvents); //避免其他控件(比如按钮、标签等)覆盖在其上面,或者其他控件阻止了事件的传递
    // 配置图表
    customPlot->addGraph();
    customPlot->graph(0)->setPen(QPen(Qt::red)); // 设置曲线1颜色
    customPlot->addGraph();
    customPlot->graph(1)->setPen(QPen(Qt::blue)); // 设置曲线2颜色

    // customPlot->graph(0)->setBrush(QBrush(QColor(0, 0, 255, 20))); // 曲线与X轴包围区的颜色
    //设置XY轴的名字
    customPlot->xAxis->setLabel("时间 (s)");
    customPlot->yAxis->setLabel("相对地面高度");

    // 初始化定时器
    dataTimer = new QTimer(this);
    connect(dataTimer, &QTimer::timeout, this, &MainWindow::updatePlot);
    dataTimer->start(20); // 每20毫秒更新一次

    // 初始化数据
    xData.clear();
    yData1.clear();
    yData2.clear();
}

注意:1.配置图表时需要再调用一次:customPlot->addGraph();
2.声明变量时需要加曲线2: QVector xData, yData1,yData2; // 数据存储

曲线显示部分修改如下:

//曲线显示事件
void MainWindow::updatePlot()
{
    // 生成新的数据点

    // 生成新信号值(如正弦波)
    *Value1() = 65 * qSin(*time1());
    *time1() += 0.1;

    // 生成新信号值(如锯齿)
    *count1()+=1;
    if(*count1()>75){
        *count1()=0;}
    *Value2() =*count1();
    // 保存数据
    xData.append(*time1());
    yData1.append(*Value1());
    yData2.append(*Value2());  // 这里保存第二条曲线的数据
    // 更新图表
    customPlot->graph(0)->setData(xData, yData1);
     customPlot->graph(1)->setData(xData, yData2);

    //这里替换之前的自动缩放
    // 自动调整Y轴范围
    customPlot->yAxis->rescale(true);

    // 更新X轴的范围(保持当前显示区间的时间轴范围)
    double lowerX = customPlot->xAxis->range().lower;
    double upperX = customPlot->xAxis->range().upper;

    // 设置X轴范围,确保X轴根据时间区间自动调整
    if (*time1() > upperX) {
        customPlot->xAxis->setRange(lowerX + 0.1, upperX + 0.1); // 保持动态显示10秒的数据
    }
   //刷新数据显示
    ui->Hvalue_label->setText(QString::number(*Value1()));
    ui->Svalue_label->setText(QString::number(*time1()));
    // 刷新图表

    customPlot->replot();
}

显示效果如下:
在这里插入图片描述

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

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

相关文章

让 Google Play 成为助力 PC 游戏增长的最佳平台

作者 / Google Play 游戏副总裁兼总经理 Aurash Mahbod 我们正在加强多平台游戏产品&#xff0c;并将在今年的游戏开发者大会 (GDC) 上发布激动人心的消息。我们将为用户带来更多游戏&#xff0c;提供更多跨设备畅玩游戏的方式&#xff0c;并进一步优化游戏体验。在游戏开发者大…

路径问题(greedy):地下城游戏

题目描述&#xff1a; 恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里&#xff0c;他必须穿过地下城并通过对抗恶魔来拯救公主。 骑士的初始健康点数为一个正整数。如果他的健…

electron框架(3.0)主程序与桥梁与渲染,以及之间的通信

每个页面程序通过渲染和主进程通信&#xff0c;主进程根据需求调用Native Api来实现功能。 实际&#xff0c;每个页面和主程序通信时&#xff0c;需要建个桥梁来管理它们的通信&#xff0c;preload.js(自己创建)&#xff0c;来管理实现通信。 ----创建preload.js定义桥梁js&a…

JS—原型与原型链:2分钟掌握原型链

个人博客&#xff1a;haichenyi.com。感谢关注 一. 目录 一–目录二–原型三–原型链 二. 原型 什么是原型&#xff1f; 每个JavaScript对象都有一个原型&#xff0c;这个原型也是一个对象。比方说 function Person(name) {this.name name; } let person new Person(&quo…

Canal 解析与 Spring Boot 整合实战

一、Canal 简介 1.1 Canal 是什么&#xff1f; Canal 是阿里巴巴开源的一款基于 MySQL 数据库增量日志解析&#xff08;Binlog&#xff09;中间件&#xff0c;它模拟 MySQL 的从机&#xff08;Slave&#xff09;行为&#xff0c;监听 MySQL 主机的二进制日志&#xff08;Binl…

图论——Prim算法

53. 寻宝(第七期模拟笔试) 题目描述 在世界的某个区域,有一些分散的神秘岛屿,每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这些岛屿上建公路,方便运输。 不同岛屿之间,路途距离不同,国王希望你可以规划建公路的方案,如何可以以最短的总公路距离将 所有岛屿联通…

1. 初识golang微服务-gRPC

单体架构 在这里插入图片描述 微服务架构 RPC架构&#xff08;远程过程调用&#xff09; 服务端实例代码&#xff1a; package mainimport ("fmt""net""net/rpc""time" )type Hello struct { }func (h Hello) SayHello(req stri…

视频翻译器免费哪个好?轻松玩转视频直播翻译

你是不是觉得看外语视频很麻烦&#xff1f;每次遇到喜欢的外语电影、电视剧或动漫&#xff0c;总是要等字幕组的翻译&#xff0c;或者因为语言不通而错过精彩的情节。 这个时候&#xff0c;掌握多语种直播翻译方案就显得尤为重要&#xff0c;有了实时字幕&#xff0c;看外语视…

Python列表1

# coding:utf-8 print("———————————— 列表 ——————————————")列表 是指一系列按照特定顺序排列的元素组成 是Python中内置的可变序列 使用[]定义列表&#xff0c;元素与元素之间使用英文的逗号分隔 列表中的元素可以是任意的数据类型列表的…

3.19学习总结

学习了Java中的面向对象的知识点 完成一道算法题&#xff0c;找树左下角的值&#xff0c;错误的以为左下角只能是最底层的左节点&#xff0c;但指的是最底层最左边的节点

服务创造未来 东隆科技携多款产品亮相慕尼黑

慕尼黑上海光博会依托于德国慕尼黑博览集团&#xff0c;自2006年首次举办以来&#xff0c;始终坚持将国内外先进的光电技术成果展示给观众&#xff0c;深度链接亚洲乃至全球的激光、光学、光电行业的优质企业及买家。如今已经成为了国内外专业观众信赖的亚洲激光、光学、光电行…

AI 时代,学习 Java 应如何入手?

一、Java 的现状&#xff1a;生态繁荣与 AI 融合的双重机遇 在 2025 年的技术版图中&#xff0c;Java 依然稳坐企业级开发的 “头把交椅”。根据行业统计&#xff0c;Java 在全球企业级应用中的市场份额仍超过 65%&#xff0c;尤其在微服务架构、大数据平台和物联网&#xff0…

LiteratureReading:[2016] Enriching Word Vectors with Subword Information

文章目录 一、文献简明&#xff08;zero&#xff09;二、快速预览&#xff08;first&#xff09;1、标题分析2、作者介绍3、引用数4、摘要分析&#xff08;1&#xff09;翻译&#xff08;2&#xff09;分析 5、总结分析&#xff08;1&#xff09;翻译&#xff08;2&#xff09;…

Object 转 JSONObject 并排除null和““字符串

public static JSONObject objToJSONObject(Object obj) throws Exception{//创建一个 HashMap 对象 map&#xff0c;用于存储对象的属性名和属性值。//key 是属性名&#xff08;String 类型&#xff09;&#xff0c;value 是属性值&#xff08;Object 类型&#xff09;Map<…

mysql5.7主从部署(docker-compose版本)

mysql5.7主从部署&#xff08;docker-compose版本&#xff09; 1:docker-compose-test.yml 文件信息 version: 3services:# MySQL 数据库mysql-master:image: mysql:5.7container_name: mysql-masterenvironment:MYSQL_ROOT_PASSWORD: 123456MYSQL_DATABASE: nacosports:- 23…

Java+Html实现前后端客服聊天

文章目录 核心组件网络通信层事件调度层服务编排层 Spring实现客服聊天技术方案对比WebScoket建立连接用户上线实现指定用户私聊群聊离线 SpringBootWebSocketHtmljQuery实现客服聊天1. 目录结构2. 配置类3. 实体类、service、controller4. ChatWebSocketHandler消息处理5.前端…

解锁 DeepSeek 安全接入、稳定运行新路径

背景 目前&#xff0c;和 DeepSeek 相关的需求总结为两类&#xff1a; 因官方 APP/Web 服务经常无法返回结果&#xff0c;各类云厂商、硬件或软件企业提供满血版或蒸馏版的 API 算力服务&#xff0c;还有不少基于开源家用计算和存储设备的本地部署方案&#xff0c;以分担 De…

【LangChain入门 1】安装

文章目录 一、安装LangChain二、安装Ollama三、Ollama下载DeepSeekR1-7b模型 本学习系列以Ollama推理后端作为大语言模型&#xff0c;展开对LangChain框架的入门学习。 模型采用deepseek-r1:7b。 毕竟是免费开源的&#xff0c;下载过程耐心等待即可。 如果可以连接外网&#x…

IvorySQL 增量备份与合并增量备份功能解析

1. 概述 IvorySQL v4 引入了块级增量备份和增量备份合并功能&#xff0c;旨在优化数据库备份与恢复流程。通过 pg_basebackup 工具支持增量备份&#xff0c;显著降低了存储需求和备份时间。同时&#xff0c;pg_combinebackup 工具能够将多个增量备份合并为单个完整备份&#x…

【css酷炫效果】纯CSS实现故障文字特效

【css酷炫效果】纯CSS实现故障文字特效 缘创作背景html结构css样式完整代码基础版进阶版(3D效果) 效果图 想直接拿走的老板&#xff0c;链接放在这里&#xff1a;https://download.csdn.net/download/u011561335/90492053 缘 创作随缘&#xff0c;不定时更新。 创作背景 刚…