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 模块中用于表示图例标记的基类。这个类有几个派生类,每个派生类代表一种类型的图例标记。
以下是一些常见的派生类:
QLegendMarker::LegendMarkerTypeXY:- 代表 XY 数据系列的图例标记,通常用于折线图、散点图等。
QLegendMarker::LegendMarkerTypeBar:- 代表柱状图数据系列的图例标记。
QLegendMarker::LegendMarkerTypePieSlice:- 代表饼图数据系列的图例标记。
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)以提供特定的实现。以下是这些事件处理函数的简要说明:
- 鼠标按下事件 (
mousePressEvent):- 当鼠标按下时触发。在该函数中,你可以处理鼠标按下时的逻辑,如获取鼠标坐标、进行拖拽等。
- 鼠标释放事件 (
mouseReleaseEvent):- 当鼠标释放时触发。你可以在该函数中处理鼠标释放时的逻辑,如执行点击操作。
- 鼠标移动事件 (
mouseMoveEvent):- 当鼠标移动时触发。在该函数中,你可以处理鼠标移动时的逻辑,如实时更新鼠标位置、进行拖拽操作等。
- 鼠标滚轮事件 (
wheelEvent):- 当鼠标滚轮滚动时触发。你可以在该函数中处理鼠标滚轮事件,如放大缩小、滚动视图等。
- 键盘按下事件 (
keyPressEvent):- 当键盘按键被按下时触发。在该函数中,你可以处理键盘按下时的逻辑,如捕捉特定按键的按下。
- 键盘抬起事件 (
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_NAMESPACE
class QWChartView : public QChartView
{
Q_OBJECT
private:
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,用于处理鼠标和键盘事件,实现了一些基本的交互功能。
以下是对这段代码的总结:
- 鼠标左键按下 (
mousePressEvent):- 记录鼠标左键按下时的起始点,用于后续矩形框缩放操作。
- 鼠标移动事件 (
mouseMoveEvent):- 发射鼠标移动信号,可以用于实时显示鼠标位置等。
- 鼠标左键释放 (
mouseReleaseEvent):- 获取矩形框的结束点,创建矩形框,并使用
zoomIn方法在矩形框内进行缩放。 - 如果是右键点击,使用
zoomReset方法重置缩放。
- 获取矩形框的结束点,创建矩形框,并使用
- 鼠标滚轮事件 (
wheelEvent):- 根据滚轮滚动方向,调整
g_x的值,然后使用zoom方法进行缩放。
- 根据滚轮滚动方向,调整
- 按键控制 (
keyPressEvent):- 根据按下的键执行相应的操作,如放大、缩小、左移、右移、上移、下移等。
- 特定按键的操作使用
zoom、scroll或zoomReset方法。
- 构造函数 (
QWChartView):- 设置拖拽模式为
QGraphicsView::RubberBandDrag,启用鼠标追踪。
- 设置拖拽模式为
- 析构函数 (
~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)
{
// 获取矩形框的 endPoint
endPoint = 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则恢复到默认大小;

C++ Qt开发:Charts折线图绑定事件的更多相关文章
- iOS Charts 折线图框架的基本使用
1. 导入框架 通过 cocoapods 管理应用程序时,在 Podfile 文件中,use_frameworks! 的使用区别如下: 使用 use_frameworks! 时 dynamic fra ...
- Qt画笔实现折线图
参考:https://www.cnblogs.com/lsgxeva/p/7821550.html效果图: void BrokenLine::paintEvent(QPaintEvent *event ...
- Qt数据可视化(散点图、折线图、柱状图、盒须图、饼状图、雷达图)开发实例
目录 散点图 折线图 柱状图 水平柱状图 水平堆叠图 水平百分比柱状图 盒须图 饼状图 雷达图 Qt散点图.折线图.柱状图.盒须图.饼状图.雷达图开发实例. 在开发过程中我们会使用多各种各样的图 ...
- canvas图表详解系列(2):折线图
本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...
- qt外部数据传入实现动态的折线图绘制
在嵌入式开发中,实现数据收集与显示很常见,对于希望数据稳定的应用来说, 折现图的表现形式很符合条件. 本实现是通过qt的signal-slot来 ...
- 使用Qt开发绘制多个设备的流量曲线图(附带项目图)
一.说明: 在实际项目中,主要是使用Qt开发CS程序,当然主要是客户端.公司项目中有这个需求是实时显示多个设备的流量曲线图,设备将流量信息发给服务端,服务端再将信息通过Socket发给Qt客户端,Qt ...
- 学习Qt Charts-创建一个简单的折线图
一.Qt Charts Qt Charts是基于Qt Graphics View实现的一个图表的组件,可以用来在QT GUI程序中添加现在风格的.可交互的.以数据为中心的图表,可以用作QWidget或 ...
- Qwt开发笔记(二):Qwt基础框架介绍、折线图介绍、折线图Demo以及代码详解
前言 QWT开发笔记系列整理集合,这是目前使用最为广泛的Qt图表类(Qt的QWidget代码方向只有QtCharts,Qwt,QCustomPlot),使用多年,系统性的整理,本系列旨在系统解说并 ...
- 冒泡,setinterval,背景图的div绑定事件,匿名函数问题
1.会冒泡到兄弟元素么? $(function(){ $("#a").click(function(){alert("a")}) $("#b" ...
- Android开发学习之路-自定义控件(天气趋势折线图)
之前写了个天气APP,带4天预报和5天历史信息.所以想着要不要加一个折线图来显示一下天气变化趋势,难得有空,就写了一下,这里做些记录,脑袋不好使容易忘事. 先放一下效果: 控件内容比较简单,就是一个普 ...
随机推荐
- C++算法之旅、05 基础篇 | 第二章 数据结构
常用代码模板2--数据结构 - AcWing 笔试用数组模拟而不是结构体 使用结构体指针,new Node() 非常慢,创建10万个节点就超时了,做笔试题不会用这种方式(优化是提前初始化好数组,但这样 ...
- 地表最帅缓存Caffeine
简介 缓存是程序员们绕不开的话题,像是常用的本地缓存Guava,分布式缓存Redis等,是提供高性能服务的基础.今天敬姐带大家一起认识一个更高效的本地缓存--Caffeine. Caffeine Ca ...
- 如何使用Java + React计算个人所得税?
前言 在报表数据处理中,Excel公式拥有强大而多样的功能,广泛应用于各个业务领域.无论是投资收益计算.财务报表编制还是保险收益估算,Excel公式都扮演着不可或缺的角色.传统的做法是直接依赖Exce ...
- PHP对关联数组(键值对数组)遍历循环
PHP对关联数组循环遍历 $arr=array('yxb'=>20,'ylg'=>21,'lgj'=18); foreach($arr as $name=>$value) { ech ...
- Tomcat--文件上传--文件包含--(CVE-2017-12615)&&(CVE-2020-1938)
Tomcat--文件上传--文件包含--(CVE-2017-12615)&&(CVE-2020-1938) 复现环境 采用Vulfocus靶场环境进行复现,搭建操作和文章参考具体搭建教 ...
- 卷积导向快速傅里叶变换(FFT/NTT)教程
1 Forewords 卷积,但不止卷积 - FFT 漫谈 先有 FT,再有 DFT,才有 FFT 时频转换是最初的用途 发现单位根优秀性质,James Cooley, John Tukey 发明现代 ...
- springboot整合redis报错:链接失败; Unable to connect to Redis
springboot整合redis报错:链接失败:org.springframework.data.redis.RedisConnectionFailureException: Unable to c ...
- 实战0-1,Java开发者也能看懂的大模型应用开发实践!!!
前言 在前几天的文章<续写AI技术新篇,融汇工程化实践>中,我分享说在RAG领域,很多都是工程上的实践,做AI大模型应用的开发其实Java也能写,那么本文就一个Java开发者的立场,构建实 ...
- 一次考试的dp题
很明显是dp 看题目的时候我们先进行初步的思考,发现一个性质 一个点时不可能被重复覆盖三次的很显然,如果一个点被覆盖了3次,这3个覆盖他的区间一定是有一个区间被完全包含的,因为有贡献的左右端点只有两个 ...
- 2020/4/29 一场令人头疼的cf。。。
今天是被安排的cf...我真的是太菜了啊...又双叒叕被机房的一群dalao吊打了... 这就是我与6年级的dalao的区别吗...我裂开了 T1:A - Exercising Walk 简单题. 就 ...