Qt:事件

news2025/3/11 6:10:20

目录

处理事件

鼠标事件

键盘事件

定时器事件

窗口事件


虽然 Qt 是跨平台的 C++ 开发框架,Qt 的很多能力其实是操作系统提供的
只不过 Qt 封装了系统的 API

事件

前面学习过信号槽:
用户进行的各种操作,就可能会产生出信号,可以给某个信号指定槽函数,当信号触发时,就能够自动的执行到对应的槽函数

事件和信号槽非常类似:
用户进行的各种操作,也会产生事件,程序员同样可以给事件关联上处理函数(处理的逻辑),当事件触发的时候,就能够执行到对应的代码

事件本身是操作系统提供的机制,Qt 也同样把操作系统事件机制进行了封装,拿到了 Qt 中
但是由于事件对应的代码编写起来不是很方便,所以 Qt 对于事件机制又进行了进一步的封装,就得到了信号槽

信号槽就是对于事件的进一步封装,事件是信号槽的底层机制

实际 Qt 开发程序过程中,绝大部分和用户之间进行的交互都是通过"信号槽"来完成的
有些特殊情况下,信号槽不一定能搞定(某个用户的动作行为,Qt 没有提供对应的信号)
此时就需要通过重写事件处理函数的形式,来手动处理事件的啊应逻辑

开发事件机制给咱们程序员,咱们就可以根据实际的需要进行更深度的定制化 diy 操作了

用户进行了很多操作,就会产生很多的事件(当然也会产生很多的信号)

下面就是开发中比较典型的事件:

不同场景下,要关注的点是不一样,这些事件的子类中就会包含一些对应的不同的属性


处理事件

让一段代码和某个事件关联起来,当事件触发的时候,就能指定到这段代码
之前信号槽这里通过 connect 来完成上述关联的

对于事件来说,还不太一样:
让当前的类,重写某个事件处理函数,这里用到的是"多态”机制
创建子类, 继承自 Qt 已有的类,在子类中重写父类的事件处理函数
后续事件触发过程中,就会通过多态这样的机制,执行到咱们自己写的子类的函数中

鼠标事件

下面都是创建 QWidget 的,当然也可以创建 QMainWindow,因为用不到工具栏,所以选择的 QWidget

鼠标进入和鼠标离开事件

下面使用上述方式,处理一下鼠标进入(enterEvent)和鼠标离开(leaveEvent)事件:
enterEvent 和 leaveEvent 函数都是虚函数,所以可以被子类重写:

图形化界面的方式创建一个 Label,鼠标进入 Label 时提示 enterEvent,离开时提示 leaveEvent:
为了能清楚看到 Label 的边框,将边框选为 Box

 效果为:

这里需要创建 QLabel 的子类,重写 enterEvent 和 leaveEvent:

类名就叫 Label,父类叫 QLabel:

按照以往的习惯,创建的 Label 类需要有一个父控件,所以在 label.h 中添加:

label.cpp 中添加:


接着在 label.h 中声明两个需要重写的函数:

注意:
要想重写父类的函数,就需要确保你这边写的函数名字和函数的参数列表都完全一致 (形参名无所谓),谨防单词拼写错误

label.cpp 实现:

(void)event 是为了消除警告,因为暂时还没用到 event 这个形参

此时运行程序,鼠标进入和移出 label 时并没有执行上述逻辑,因为:
当前在界面上创建的这个 label 其实是 QLabel,不是咱们自己写的 Label
必须要确保界面上的这个 label 是一个咱们自己定义的 Label 类的实例,才会执行到

右键图形化界面的 label,点击提升为:

输入提升的类名 Label,点击添加,再点击提升:
一定要确保你的类名以及头文件的名字,和上述自定义的类名头文件都匹配

此时右边对象树上面就是 Label 了,没提升前显示是 QLabel:

通过"提升为"这样的方式,就可以把 Qt Designer 中拖上去的控件的类型转换成自定义的控件类型

此时再运行程序,鼠标移入移出 Label 时,就会打印下面的内容了:

此时就说明当前的 enterEvent 和 leaveEvent 这两个事件就被咱们给捕获到了


通过事件获取到鼠标点击的位置

与上面的操作一样,创建一个 Label,再创建一个 Label 类,父类定为 QLabel,并对生成的 Label 的构造函数做一个调整,添加一个 QWidget* 的参数,以便于能够指定父窗口
接着再右键 Label 点击提升为,输入类名后点击提升,此时就完成了提升操作:

下面就是 mousePressEvent 函数,当鼠标按下时就会触发这个函数调用:
左键、右键、滚轮、侧键都能触发

在 label.cpp 中实现 mousePressEvent 函数:

此时鼠标在 Label 范围内点击就会打印 鼠标点击的位置坐标:
上述是以 Label 左上角位置为原点的

下面则是以屏幕左上角为原点获取坐标:

也可以加上下面的代码,来判断按下的是左键还是右键:


通过事件获取到鼠标点击释放按键

与上面的鼠标点击事件一样,下面是重写的 mouseReleaseEvent 函数:

此时就能做到获取鼠标点击释放按键:

clicked 这样的信号,就相当于是一次鼠标按下事件和一次鼠标释放事件


通过事件获取到鼠标双击按键

重写的 mouseDoubleEvent 函数如下:

鼠标第二次按下的时候,才能够识别到是"双击:

注意:
有的程序,可能是单击有一些逻辑,双击有另一些逻辑,如果我们没注意,可能双击操作就能触发单击的逻辑,可能就有 bug


通过事件获取到鼠标移动

刚才重写鼠标事件的操作,都是在自定义的 Labe| 中完成的,此时鼠标只有在 Label 范围内进行动作的时候,才能捕获到
也可以把这些操作直接放到 Widget (QWidqet 子类) 来完成,这样的话,鼠标在整个窗口中进行的各种动作都能获取到了

所以直接在 widget.h widget.cpp 中重写 mouseMoveEvent 函数:

此时运行程序并没有效果

鼠标移动不同于鼠标按下
随便移动一下鼠标,就会产生出大量的鼠标移动事件,当你进行捕获事件的时候,尤其是在这里再进行一些复杂逻辑的时候,程序负担就很重,很容易产生卡顿之类的情况
Qt 为了保证程序的流畅性,默认情况下不会对鼠标移动进行追踪,鼠标移动的时候不会调用mouseMoveEvent,除非显式告诉 Qt 就要追踪鼠标位置

所以需要在 Widget 的构造函数中设置:

此时稍微一动鼠标,就会一直打印,如果移动的比较快,就会明显出现打印卡顿的情况:


通过事件获取到鼠标滚轮的滚动动作

在 QWheelEvent 中 通过 delta() 获取到这次事件鼠标滚轮滚动了多远

同样在 widget.h widget.cpp 中重写 wheelEvent 函数:

滚轮往下滚动就打印 -120,往上滚动就打印 120:

我们也可以在 Widget 类中新增 int total,初始化为0,就能在 wheelEvent 函数中实现统计滚轮滚动的距离了:

效果为:

就可以根据滚轮滚动的操作实现特定的功能,比如可以通过滚轮去缩放字体大小,可以把滚轮滚动的距离映射到具体的数值上,就可以实现类似的效果了


键盘事件

处理键盘按键事件

我们前面学习过的 QShortCut,这是信号槽机制封装过的,获取键盘按键的方式

站在更底层的角度,也可以通过事件获取到当前用户键盘按下的情况

依旧是在 widget.h widget.cpp 中重写 keyPressEvent 函数:

按下 ABCDEF 的效果为,可以发现每一个按钮都对应一个数字:

如果想得知是否按下了具体的某一个键,以 A 为例,代码改为:

也有些场景是组合键 Ctrl + A :


定时器事件

前面学习了QTimer 实现定时器功能
在 QTimer 背后是 QTimerEvent 定时器事件进行支撑的

QObject 提供了一个 timerEvent 这个函数,可以通过定时器,周期性的触发一些操作
里面需要搭配 startTimer 启动定时器,killTimer 关闭定时器 使用

下面通过图形化的方式,拖动一个 LCD Number,初始值改为 10 :

此处 startTimer 的返回值 timerld 类似于 Linux 中的文件描述符,起到的是身份标识的效果

因为后面程序可能还会用到 timerld,所以在 widget.h 中的构造函数定义为类内成员:

在 widget.h widget.cpp 中重写 timerEvent 函数:

运行程序,每隔一秒-1,直到0就停止:

使用 timerEvent 比 QTimer 还是要更复杂一点,手动管理 timerld,还需要区分这次函数调用是哪个 timer 引起的
后续实际开发中,使用 QTimer 即可


窗口事件

  • moveEvent 窗口移动时触发的事件
  • resizeEvent 窗口大小改变时触发的事件

 moveEvent

QMoveEvent 中有下面两个常用的方法:

resizeEvent

QResizeEvent 中有下面两个常用的方法:


在 widget.h widget.cpp 中重写 moveEvent 和 resizeEvent函数:

如果移动 widget 窗口或调整 widget 窗口大小,下面就会打印:


Qt:事件相关知识到此结束

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

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

相关文章

3个 Vue Scoped 的核心原理

大家好,我是大澈!一个喜欢结交朋友、喜欢编程技术和科技前沿的老程序员👨🏻‍💻,关注我,科技未来或许我能帮到你! 先用一句话概括 Vue Scoped 的核心原理:Vue 的 scoped…

物联网IoT系列之MQTT协议基础知识

文章目录 物联网IoT系列之MQTT协议基础知识物联网IoT是什么?什么是MQTT?为什么说MQTT是适用于物联网的协议?MQTT工作原理核心组件核心机制 MQTT工作流程1. 建立连接2. 发布和订阅3. 消息确认4. 断开连接 MQTT工作流程图MQTT在物联网中的应用 …

ubuntu 20.04 C++ 源码编译 cuda版本 opencv4.5.0

前提条件是安装好了cuda和cudnn 点击下载: opencv_contrib4.5.0 opencv 4.5.0 解压重命名后 进入opencv目录,创建build目录 “CUDA_ARCH_BIN ?” 这里要根据显卡查询一下,我的cuda是11,显卡1650,所以是7.5 查询方法1&#xff1…

2025-03-07 学习记录--C/C++-PTA 习题8-5 使用函数实现字符串部分复制

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 二、代码&#xff08;C语言&#xff09;⭐️ #include <stdio.h> #define MAXN 20void strmcpy( char…

江科大51单片机笔记【10】蜂鸣器(上)

一、蜂鸣器 1.原理 蜂鸣器是一种将电信号转换为声音信号的器件&#xff0c;常同来产生设备的按键音、报警音等提示信号蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器&#xff08;外观基本一样&#xff09;有源蜂鸣器&#xff1a;内部自带振荡源&#xff0c;将正负极接上直流…

最新版本WebContext构造函数-避坑

import org.thymeleaf.context.IWebContext; import org.thymeleaf.context.WebContext; 当你想把页面信息全部获取出来存到redis缓存中使用时&#xff0c;SpringWebContext在Spring5中报错 SpringWebContext ctx new SpringWebContext(request, response,request.getServlet…

忘记dedecms后台超级管理员账号和密码的解决方案

解决方案&#xff1a; 方案一、数据库修改&#xff1a; 1、前提是您能登录到数据库后台&#xff0c;登录MySQL数据库管理工具&#xff08;如phpMyAdmin&#xff09; 2、打开数据库中的 dede_admin 表&#xff0c;找到管理员记录&#xff0c;将 pwd 字段的值改成 f297a57a5a7…

Kubernetes中的 iptables 规则介绍

#作者&#xff1a;邓伟 文章目录 一、Kubernetes 网络模型概述二、iptables 基础知识三、Kubernetes 中的 iptables 应用四、查看和调试 iptables 规则五、总结 在 Kubernetes 集群中&#xff0c;iptables 是一个核心组件&#xff0c; 用于实现服务发现和网络策略。iptables 通…

Windows 11下Git Bash执行cURL脚本400问题、CMD/PowerShell不能执行多行文本等问题记录及解决方案

问题 在Postman里可成功执行的POST请求&#xff1a; 找到Postman的Code 因为cURL基本上算是行业标准&#xff0c;所以Postman默认选中cURL&#xff0c;支持切换不同的开发语言&#xff1a; 点击上图右上角的复制按钮&#xff0c;得到cURL脚本。 Windows 11家庭版&#xff…

利用LLMs准确预测旋转机械(如轴承)的剩余使用寿命(RUL)

研究背景 研究问题:如何准确预测旋转机械(如轴承)的剩余使用寿命(RUL),这对于设备可靠性和减少工业系统中的意外故障至关重要。研究难点:该问题的研究难点包括:训练和测试阶段数据分布不一致、长期RUL预测的泛化能力有限。相关工作:现有工作主要包括基于模型的方法、数…

记录小白使用 Cursor 开发第一个微信小程序(二):创建项目、编译、预览、发布(250308)

文章目录 记录小白使用 Cursor 开发第一个微信小程序&#xff08;二&#xff09;&#xff1a;创建项目、编译、预览、发布&#xff08;250308&#xff09;一、创建项目1.1 生成提示词1.2 生成代码 二、编译预览2.1 导入项目2.2 编译预览 三、发布3.1 在微信开发者工具进行上传3…

游戏引擎学习第146天

音高变化使得对齐读取变得不可能&#xff0c;我们可以支持循环声音了。 我们今天的目标是完成之前一段时间所做的音频代码。这个项目并不依赖任何引擎或库&#xff0c;而是一个教育项目&#xff0c;目的是展示从头到尾运行一个游戏所需要的全部代码。无论你对什么方面感兴趣&a…

Java 大视界 -- Java 大数据在智能体育赛事运动员表现分析与训练优化中的应用(122)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

线性代数之矩阵特征值与特征向量的数值求解方法

文章目录 前言1. 幂迭代法&#xff08;Power Iteration&#xff09;幂法与反幂法求解矩阵特征值幂法求最大特征值编程实现补充说明 2. 逆幂迭代法&#xff08;Inverse Iteration&#xff09;移位反幂法 3. QR 算法&#xff08;QR Algorithm&#xff09;——稠密矩阵理论推导编程…

SparkAi系统体验

DeepSeek-R1-671B大模型满血版私有化部署高可用教程-SparkAi系统集成图文教程 一、SparkAI是什么二、功能模块介绍系统快速体验 三、系统功能模块3.1 AI全模型支持/插件系统3.2 AI智能体应用3.3 AI专业绘画3.4 AI视频生成3.5 Dall-E2/E3/E4绘画3.6 智能思维导图生成3.7 AI绘画广…

视频录像机视频通道是指什么

视频录像机的视频通道是指摄像机在监控矩阵或硬盘录像机设备上的视频输入的物理位置。 与摄像头数量关系&#xff1a;在视频监控系统中&#xff0c;有多少个摄像头就需要多少路视频通道&#xff0c;通道数量决定了视频录像机可接入摄像头的数量&#xff0c;一般硬盘录像机有4路…

【Unity】 HTFramework框架(六十一)Project窗口文件夹锁定器

更新日期&#xff1a;2025年3月7日。 Github源码&#xff1a;[点我获取源码] Gitee源码&#xff1a;[点我获取源码] 索引 Project窗口文件夹锁定器框架文件夹锁定自定义文件夹锁定限制条件 Project窗口文件夹锁定器 在Project窗口中&#xff0c;文件夹锁定器能够为任何文件夹加…

INFINI Labs 产品更新 | Easysearch 增加异步搜索等新特性

INFINI Labs 产品更新发布&#xff01;此次更新&#xff0c;Easysearch 增加了新的功能和数据类型&#xff0c;包括 wildcard 数据类型、Point in time 搜索 API、异步搜索 API、数值和日期字段的 doc-values 搜索支持&#xff0c;Console 新增了日志查询功能。 INFINI Easyse…

3.6c语言

#define _CRT_SECURE_NO_WARNINGS #include <math.h> #include <stdio.h> int main() {int sum 0,i,j;for (j 1; j < 1000; j){sum 0;for (i 1; i < j; i){if (j % i 0){sum i;} }if (sum j){printf("%d是完数\n", j);}}return 0; }#de…

Docker基础篇——Ubuntu下Docker安装

大家好我是木木&#xff0c;在当今快速发展的云计算与云原生时代&#xff0c;容器化技术蓬勃兴起&#xff0c;Docker 作为实现容器化的主流工具之一&#xff0c;为开发者和运维人员带来了极大的便捷 。下面我们一起进行Docker安装。 Docker的官方Ubuntu安装文档&#xff0c;如…