C++ Qt开发:Charts折线图绑定事件

Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QCharts折线图的常用方法及灵活运用。

在上一篇文章中笔者介绍了关于QCharts绘图组件的详细使用方法及接口,本章将继续为绘图组件绑定事件,通常在未绑定事件的图形上所有的元素都是被禁用状态的,我们无法直接操作这些功能,通过绑定图形组件事件将可以实现对图形的各种操作模式,例如可以控制图形的大小,控制线条的显示与消除等。

首先,我们来实现动态显示与隐藏线条功能,还是使用之前的代码这里稍作改进增加一个十五分钟负载统计,接着我们在MainWindow主构造函数中通过markers()得到所有的标签,然后先调用disconnect()断开信号的连接,接着在使用connect()将当前上方三个按钮进行绑定,当按钮被点击则会触发on_LegendMarkerClicked()槽函数;

// 图例被点击后触发
foreach (QLegendMarker* marker, chart->legend()->markers())
{QObject::disconnect(marker, SIGNAL(clicked()), this, SLOT(on_LegendMarkerClicked()));QObject::connect(marker, SIGNAL(clicked()), this, SLOT(on_LegendMarkerClicked()));
}

接着,我们需要来实现on_LegendMarkerClicked()槽函数的功能,这里需要介绍一个类,QLegendMarker 类是 Qt Charts 模块中用于表示图例标记的基类。这个类有几个派生类,每个派生类代表一种类型的图例标记。

以下是一些常见的派生类:

  1. QLegendMarker::LegendMarkerTypeXY
    • 代表 XY 数据系列的图例标记,通常用于折线图、散点图等。
  2. QLegendMarker::LegendMarkerTypeBar
    • 代表柱状图数据系列的图例标记。
  3. QLegendMarker::LegendMarkerTypePieSlice
    • 代表饼图数据系列的图例标记。
  4. QLegendMarker::LegendMarkerTypeArea
    • 代表面积图数据系列的图例标记。

这些类型分别对应于不同种类的数据系列,因为不同类型的数据系列可能需要不同的图例标记。当你处理 QLegendMarker 的点击事件时,通过检查标记的类型,你可以判断点击的是哪一种类型的图例标记,并作出相应的处理,比如切换数据系列的可见性。

// 在槽函数中获取图例标记的类型
void MainWindow::on_LegendMarkerClicked()
{QLegendMarker* marker = qobject_cast<QLegendMarker*>(sender());// 获取图例标记的类型QLegendMarker::LegendMarkerType type = marker->type();// 根据标记的类型执行相应的操作switch (type){case QLegendMarker::LegendMarkerTypeXY:// 处理 XY 数据系列的图例标记break;case QLegendMarker::LegendMarkerTypeBar:// 处理柱状图数据系列的图例标记break;case QLegendMarker::LegendMarkerTypePieSlice:// 处理饼图数据系列的图例标记break;case QLegendMarker::LegendMarkerTypeArea:// 处理面积图数据系列的图例标记break;default:break;}
}

上述示例中,我们通过 QLegendMarker::type() 方法获取了图例标记的类型,并根据类型执行相应的操作。其中marker变量则是用户点击过的标签指针,这可以帮助你在处理图例标记点击事件时更灵活地根据标记的类型进行不同的逻辑处理。

为了实现点击后隐藏与显示特定线条,我们可以这样来实现,首先通过marker得到被点击案例的指针,通过marker->type()来检查类型是否为LegendMarkerTypeXY,如果是就通过根据数据可见性来设置透明度,也就是如果可见那就不可见,如果不可见就可见的逻辑。数据系列不可见,透明度 alpha 设置为 0.5,否则保持为 1.0。

// 槽函数:处理图例标记点击事件,显示或隐藏与之关联的数据系列
void MainWindow::on_LegendMarkerClicked()
{// 将发送者强制转换为 QLegendMarker 类型QLegendMarker* marker = qobject_cast<QLegendMarker*>(sender());// 检查标记的类型switch (marker->type()){case QLegendMarker::LegendMarkerTypeXY:{// 切换数据系列的可见性marker->series()->setVisible(!marker->series()->isVisible());// 设置标记可见marker->setVisible(true);// 根据数据系列的可见性设置标记的透明度qreal alpha = 1.0;if (!marker->series()->isVisible())alpha = 0.5;// 调整标记的标签刷颜色透明度QColor color;QBrush brush = marker->labelBrush();color = brush.color();color.setAlphaF(alpha);brush.setColor(color);marker->setLabelBrush(brush);// 调整标记的刷颜色透明度brush = marker->brush();color = brush.color();color.setAlphaF(alpha);brush.setColor(color);marker->setBrush(brush);// 调整标记的画笔颜色透明度QPen pen = marker->pen();color = pen.color();color.setAlphaF(alpha);pen.setColor(color);marker->setPen(pen);break;}default:break;}
}

总体而言,这段代码的作用是在图例标记被点击时,切换与之关联的数据系列的可见性,并通过调整标记的颜色透明度来反映数据系列的可见性状态。透明度的调整使得图例标记在图表中的可视效果更符合数据系列的可见性。如下图所示,我们只保留一个十五分钟负载,将前两个隐藏掉。

接着,我们继续增加一个折线图动态预览功能,通过使用该功能可以对特定区域进行选择放大缩小,读者可通过键盘案件进行缩放也可通过鼠标滚轮和左右键选中缩放,该功能在图形预览中也是最常见的。

为了实现该功能,需要先来了解三个常用键盘鼠标库,第一个是QMouseEvent该库主要用于实现对鼠标左键或右键的单击、释放等操作的监控,对鼠标滚轮的响应则通过QWheeEvent来监控,而键盘事件则通过QKeyEvent类来监控。

由于键盘鼠标事件很简单所以此处将不再重点介绍如何实现,在使用这些事件处理函数时,你只需要在你的类中进行重写(override)以提供特定的实现。以下是这些事件处理函数的简要说明:

  1. 鼠标按下事件 (mousePressEvent):
    • 当鼠标按下时触发。在该函数中,你可以处理鼠标按下时的逻辑,如获取鼠标坐标、进行拖拽等。
  2. 鼠标释放事件 (mouseReleaseEvent):
    • 当鼠标释放时触发。你可以在该函数中处理鼠标释放时的逻辑,如执行点击操作。
  3. 鼠标移动事件 (mouseMoveEvent):
    • 当鼠标移动时触发。在该函数中,你可以处理鼠标移动时的逻辑,如实时更新鼠标位置、进行拖拽操作等。
  4. 鼠标滚轮事件 (wheelEvent):
    • 当鼠标滚轮滚动时触发。你可以在该函数中处理鼠标滚轮事件,如放大缩小、滚动视图等。
  5. 键盘按下事件 (keyPressEvent):
    • 当键盘按键被按下时触发。在该函数中,你可以处理键盘按下时的逻辑,如捕捉特定按键的按下。
  6. 键盘抬起事件 (keyReleaseEvent):
    • 当键盘按键被抬起时触发。你可以在该函数中处理键盘抬起时的逻辑,如释放某个按键的状态。

在附件中笔者将代码整理成了Keyboard and mouse文件,读者可自行打开该文件编译运行观察键盘鼠标事件是如何被重写的。

要对一个QChart图表进行鼠标和按键操作,需要在QChartView组件里对鼠标和按键事件进行处理,这就需要自定义一个从QChartView继承的类,此处我们自定义一个QWChartView类,它从QChartView继承而来,对鼠标和按键事件进行处理QWChartView类的定义如下:

#ifndef QWCHARTVIEW_H
#define QWCHARTVIEW_H
#include <QMouseEvent>
#include <QWheelEvent>
#include <QKeyEvent>
#include <iostream>
#include <QtCharts>
#include <QChartView>QT_CHARTS_USE_NAMESPACEclass QWChartView : public QChartView
{Q_OBJECTprivate:QPoint  beginPoint;  // 选择矩形区的起点QPoint  endPoint;    // 选择矩形区的终点protected:// 鼠标左键按下void mousePressEvent(QMouseEvent *event);// 鼠标移动void mouseMoveEvent(QMouseEvent *event);// 鼠标释放左键void mouseReleaseEvent(QMouseEvent *event);// 鼠标滚轮事件void wheelEvent(QWheelEvent *event);// 按键事件void keyPressEvent(QKeyEvent *event);public:explicit QWChartView(QWidget *parent = 0);~QWChartView();signals:// 鼠标移动信号在mouseMoveEvent()事件中触发void mouseMovePoint(QPoint point);
};#endif // QWCHARTVIEW_H

如下所示的代码是一个自定义的 Qt 图表视图类 QWChartView,用于处理鼠标和键盘事件,实现了一些基本的交互功能。

以下是对这段代码的总结:

  1. 鼠标左键按下 (mousePressEvent):
    • 记录鼠标左键按下时的起始点,用于后续矩形框缩放操作。
  2. 鼠标移动事件 (mouseMoveEvent):
    • 发射鼠标移动信号,可以用于实时显示鼠标位置等。
  3. 鼠标左键释放 (mouseReleaseEvent):
    • 获取矩形框的结束点,创建矩形框,并使用 zoomIn 方法在矩形框内进行缩放。
    • 如果是右键点击,使用 zoomReset 方法重置缩放。
  4. 鼠标滚轮事件 (wheelEvent):
    • 根据滚轮滚动方向,调整 g_x 的值,然后使用 zoom 方法进行缩放。
  5. 按键控制 (keyPressEvent):
    • 根据按下的键执行相应的操作,如放大、缩小、左移、右移、上移、下移等。
    • 特定按键的操作使用 zoomscrollzoomReset 方法。
  6. 构造函数 (QWChartView):
    • 设置拖拽模式为 QGraphicsView::RubberBandDrag,启用鼠标追踪。
  7. 析构函数 (~QWChartView):
    • 析构函数为空,未添加特定的析构逻辑。

总体而言,这段代码实现了一个基本的图表视图类,支持鼠标交互和键盘控制,提供了图表的缩放、移动等功能。这样的自定义视图类通常用于定制图表的交互行为,以满足特定的应用需求。

#include "qwchartview.h"
#include <QChartView>// 鼠标左键按下
void QWChartView::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton){// 记录左键按下时的起始点beginPoint = event->pos();}// 调用基类的鼠标按下事件处理函数QChartView::mousePressEvent(event);
}// 鼠标移动事件
void QWChartView::mouseMoveEvent(QMouseEvent *event)
{// 获取当前鼠标的位置QPoint point = event->pos();// 发射鼠标移动信号emit mouseMovePoint(point);// 调用基类的鼠标移动事件处理函数QChartView::mouseMoveEvent(event);
}// 鼠标左键释放
void QWChartView::mouseReleaseEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton){// 获取矩形框的 endPointendPoint = event->pos();// 创建矩形框QRectF rectF;rectF.setTopLeft(this->beginPoint);rectF.setBottomRight(this->endPoint);// 在矩形框内进行缩放this->chart()->zoomIn(rectF);}else if (event->button() == Qt::RightButton){// 右键点击时,重置缩放this->chart()->zoomReset();}// 调用基类的鼠标释放事件处理函数QChartView::mouseReleaseEvent(event);
}// 鼠标滚轮事件
qint16 g_x = 0;
void QWChartView::wheelEvent(QWheelEvent *event)
{// 当滚轮向上滑if (event->delta() > 0){g_x = g_x + 1;this->chart()->zoom(g_x);}// 当滚轮向下滑else{g_x = g_x - 1;this->chart()->zoom(g_x);}
}// 按键控制
void QWChartView::keyPressEvent(QKeyEvent *event)
{switch (event->key()){case Qt::Key_Plus:// 按 "+" 键放大chart()->zoom(1.2);break;case Qt::Key_Minus:// 按 "-" 键缩小chart()->zoom(0.8);break;case Qt::Key_Left:// 按左箭头键左移chart()->scroll(10, 0);break;case Qt::Key_Right:// 按右箭头键右移chart()->scroll(-10, 0);break;case Qt::Key_Up:// 按上箭头键上移chart()->scroll(0, -10);break;case Qt::Key_Down:// 按下箭头键下移chart()->scroll(0, 10);break;case Qt::Key_PageUp:// 按 PageUp 键上移chart()->scroll(0, 50);break;case Qt::Key_PageDown:// 按 PageDown 键下移chart()->scroll(0, -50);break;case Qt::Key_Home:// 按 Home 键重置缩放chart()->zoomReset();break;default:// 其他键交给基类处理QGraphicsView::keyPressEvent(event);}
}// 设置拖拽模式和鼠标追踪
QWChartView::QWChartView(QWidget *parent) : QChartView(parent)
{this->setDragMode(QGraphicsView::RubberBandDrag);this->setMouseTracking(true);
}// 析构函数
QWChartView::~QWChartView()
{
}

运行上述代码,则可以通过点击顶部按钮实现显示隐层不同的折线图,通过左键拖拽的方式则可以选择一个矩形区域并对该区域进行放大与缩小操作,按下鼠标右键则调用zoomReset()将图形恢复到默认大小;

由于程序中绑定了keyPressEvent键盘监控事件,当按下键盘上下左右时则通过scroll()调整图形的位置,通过按下小键盘中的+-符号则通过scroll()放大与缩小图形,通过按下Home则恢复到默认大小;

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

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

相关文章

华为OD机试 - 学生方阵 - 矩阵(Java 2023 B卷 200分)

目录 专栏导读一、题目描述二、输入描述三、输出描述1、输入2、输出 四、解题思路1、题目解析2、解体思路 五、Java算法源码再重新读一遍题目&#xff0c;看看能否优化一下~ 六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导…

浏览器加粗字体显示异常

浏览器加粗的字体模糊虚化 如果在css中设置了普通的字体样式 font-face&#xff0c;使用了 font-weight: bold 的字体会在浏览器页面中会显示模糊虚化的现象&#xff0c;而正常的字体没有这种情况&#xff0c;显示的情况根据不同的浏览器会有区别。 * 出现轻微模糊虚化效果&am…

设计模式--桥接模式

实验9&#xff1a;桥接模式 本次实验属于模仿型实验&#xff0c;通过本次实验学生将掌握以下内容&#xff1a; 1、理解桥接模式的动机&#xff0c;掌握该模式的结构&#xff1b; 2、能够利用桥接模式解决实际问题。 [实验任务]&#xff1a;两个维度的桥接模式 用桥接模式…

什么是OAuth2.0

前言 OAuth&#xff08;Open Authorization&#xff09;是一个关于授权&#xff08;authorization&#xff09;的开放网络标准&#xff0c;允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息&#xff0c;而不需要将用户名和密码提供给第三方移动应用或分享他们数…

Netty组件基础

Netty入门简介 netty是一个异步、基于事件驱动的网络应用框架&#xff0c;用于快速开发可维护、高性能的网络服务器和客户端。 Netty优势 Netty解决了TCP传输问题&#xff0c;如黏包、半包问题&#xff0c;解决了epoll空轮询导致CPU100%的问题。并且Netty对API进行增强&#xf…

taro小程序指定@代表

1.ts.config.json "paths": {"/*": ["./src/*"] } config/index.js const path require(path) alias: {: path.resolve(__dirname, .., src) },

Codeforces Round 917 (Div. 2)(A~D)

A - Least Product Solution 观察发现&#xff0c;对于 a i < 0 a_i<0 ai​<0&#xff0c;操作后 a i a_i ai​ 不会变得更小&#xff0c; a i > 0 a_i>0 ai​>0&#xff0c;操作后 a i a_i ai​ 不会变得更大。所以&#xff0c;当 ∏ i 1 n a i ≥ 0…

Python如何将图片转换成字符

PIL(Python Image Library)库是Python平台上一个功能强大的图像处理标准库&#xff0c;支持图像的存储、显示和处理&#xff0c;几乎可以处理所有图片格式&#xff0c;如图像的压缩、裁剪、叠加、添加文字等等。 安装PIL库:pip install pillow from PIL import Image ascii_cha…

【期末复习】微信小程序复习大纲( 1- 5 章)

前言&#xff1a; 这周开始进入期末复习周&#xff0c;没时间看C/C、linux等知识了&#xff0c;先把期末考试必考的知识捋一遍。 目录 第一章 微信小程序入门 一、填空题 二、判断题 三、选择题 四、简答题 第二章 微信小程序页面制作 一、填空题 二、判…

【Java中创建对象的方式有哪些?】

✅Java中创建对象的方式有哪些&#xff1f; ✅使用New关键字✅使用反射机制✅使用clone方法✅使用反序列化✅使用方法句柄✅ 使用Unsafe分配内存 ✅使用New关键字 这是我们最常见的也是最简单的创建对象的方式&#xff0c;通过这种方式我们还可以调用任意的构造函数 (无参的和有…

mybatis的二级缓存使用以及禁用

目录 mybatis 二级缓存配置有两处 全局设置 mapper 设置 测试代码 执行结果 源码执行逻辑 创建 SqlSession 二级缓存配置是否添加 解析 cache 标签 XMLMapperBuilder MapperBuilderAssistant CacheBuilder PerpetualCache SerializedCache LoggingCache 将 cach…

Grafana二进制部署并配置prometheus数据源

1、获取grafna二进制安装包 https://grafana.com/grafana/download?pggraf&plcmtdeploy-box-1 grafana官网下载地址 [rootambari-hadoop1 ~]# cd /opt/module/grafana/ [rootambari-hadoop1 grafana]# pwd /opt/module/grafana2、在安装自己的安装目录执行 wget https:…

在killercoda中的一次apiserver异常追查思路

笔者&#xff1a; 最近在准备cks考试&#xff0c; 然后又发现了killercoda这个能够提供模拟考试环境的平台。它提供了很棒的引导&#xff0c;教你一步步追查问题&#xff0c;形成一整套追查思路&#xff0c;我觉得很不错&#xff0c;特此分享。 准备工作 首先还是需要养成配置…

spark:RDD编程(Python版)

RDD运行原理 RDD设计背景 许多选代目前的MapReduce框架都是把中间结果写入到稳定存储 (比如磁盘)中带来了大量的数据复制、磁盘IO和序列化开销 RDD就是为了满足这种需求而出现的&#xff0c;它提供了一个抽象的数据架构&#xff0c;我们不必担心底层数据的分布式特性&#xf…

useRef语法讲解

useRef useRef 用法 import { useRef, useState } from react import ./App.cssfunction App() {const userRef useRef<HTMLInputElement>(null)const [val, setVal] useState()const handleClick () > {userRef.current?.focus()setVal(userRef.current?.valu…

windows中python3创建虚拟环境

当我们在创建一个python项目时&#xff0c;经常需要安装一堆库&#xff0c;然后转到另一个项目&#xff0c;却发现依赖冲突了&#xff0c;人都麻了。所以创建虚拟环境就是解决这个大麻烦的。 什么是虚拟环境&#xff1f; 虚拟环境是Python的一个工具&#xff0c;支持我们在一…

Nginx安装与文件服务器实现

1. 概述 Nginx是一个高性能的反向代理和web服务器软件&#xff0c;特点是系统资源消耗低、高性能、高并发、扩展性好。一个进程可以处理多个请求&#xff0c;并且是非阻塞式响应。 windows安装安装包下载地址&#xff1a;https://nginx.org/en/download.html下载之后解压运行n…

tensorboard可视化——No dashboards are active for the current data set.

No dashboards are active for the current data set. 出现问题的原因是事件的路径未用绝对路径&#xff0c;tensorboard --logdir./runs --port6007 改为tensorboard --logdirD:\Code\Python\Study\CL\hat-master\hat-master\run s\one --port6007就好了

acwing linux docker教程

终章 听着名字还挺伤感的哈哈哈其实是Linux的终章&#xff0c;感谢大家这段时间的阅读&#xff0c;这段使时间我为了给大家清楚的讲解一下Linux自己也是很认真的学习了一遍&#xff0c;自己提升了也不少。其实最近学校里面是讲了Linux和windows server 2019搭载DNS、web、ftp服…

[渗透测试学习] Manager - HackTheBox

文章目录 信息搜集 nmap扫描一下端口 nmap -sV -sC -p- -v --min-rate 1000 10.10.11.236扫出来很多端口&#xff0c;其中80端口有http服务&#xff0c;88端口是采用一个身份验证协议kerberos&#xff0c;以及NetBIOS-SSN&#xff08;端口139&#xff09;和Microsoft-DS&#…