Qt开发⑨Qt的事件_事件处理_按键事件和鼠标事件

目录

1. 事件简介

2. 事件的处理

3. 键盘按键事件

3.1 单个按键

3.2 组合按键

4. 鼠标事件

4.1 鼠标单击事件

4.2 鼠标释放事件

4.3 鼠标双击事件

4.4 鼠标移动事件

4.5 滚轮事件

5. 定时器

5.1 QTimerEvent 类

5.2 QTimer 类

6. 事件分发器

7. 事件过滤器

本篇完。


1. 事件简介

        事件是应用程序内部或者外部产生的事情或者动作的统称。在 Qt 中使用一个对象来表示一个事件。所有的 Qt 事件均继承于抽象类 QEvent。事件是由系统或者 Qt 平台本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件是在用户操作时发出,如键盘事件、鼠标事件等,另一些事件则是由系统本身自动发出,如定时器事件。

常见的 Qt 事件如下:

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

常见事件描述:

事件名称描述
鼠标事件鼠标左键、鼠标右键、鼠标滚轮,鼠标的移动,鼠标按键的按下和松开
键盘事件按键类型、按键按下、按键松开
定时器事件定时时间到达
进入离开事件鼠标的进入和离开
滚轮事件鼠标滚轮滚动
绘屏事件重绘屏幕的某些部分
显示隐藏事件窗口的显示和隐藏
移动事件窗口位置的变化
窗口事件是否为当前窗口
大小改变事件窗口大小改变
焦点事件键盘焦点移动
拖拽事件用鼠标进行拖拽

2. 事件的处理

事件处理一般常用的方法为:重写相关的 Event 函数。

        在 Qt 中,几乎所有的 Event 函数都是虚函数,所以可以重新实现。比如:在实现鼠标的进入和离开事件时,直接重新实现 enterEvent() 和 leaveEvent() 即可。enterEvent() 和 leaveEvent() 函数原型如下:


示例一

(1)新建 Qt 项目

基类选择 QWidget,同时勾选 UI 界面文件:


(2)设计 UI 文件


(3)在项目中新添加一个类

先选中项目名称 QEvent,点击鼠标右键,选择 add new ... ,弹出如下对话框:


(4)定义类名并选择基类


(5)此时项目中会新添加以下两个文件


(6)在帮助文档中查找对应的内容


(7)点击 “显示” 之后:


(8)复制 enterEvent(),粘贴在项目文件 "label.h" 中

要想重写父类的函数就需要确保写的函数名字和函数的参数列表完全一致(形参名无所谓)。


(9)重写 enterEvent() 和 leaveEvent() 方法


(10)在 UI 文件中选中 Label,右键 ——> 提升为...


(11)当点击 “提升为...” 之后

        通过 “提升为...” 这样的方式就可以把 Qt Designer 中托上去的控件的类型转换成自定义的控件类型。


(12)修改基类


(13)执行效果

        当鼠标进入设计好的标签之后,就会在应用程序输出栏中打印:enterEvent;鼠标移出设计好的标签之后,就会在应用程序输出栏中打印:leaveEvent。

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


示例二,当鼠标点击时,获取对应的坐标值:

(1)在 label.h 中声明 mousePressEvent() 方法


(2)在 label.cpp 中重写 mousePressEvent() 方法

鼠标左键点击时,打印对应的坐标值,鼠标右键点击时,打印基于屏幕的坐标。

实现效果如下:


3. 键盘按键事件

        Qt 中的按键事件是通过 QKeyEvent 类来实现的。当键盘上的按键被按下或者被释放时,键盘事件便会触发。

在帮助文档中查找 QKeyEvent 类如下:

查找按键事件中所有的按键类型:在帮助文档中输入:Qt::Key,如下图:


3.1 单个按键

示例:当某个按键被按下时,输出:某个按键被按下了;

1. 新建项目,在头文件 "widget.h" 中声明虚函数 keyPressEvent();如下图:


2. 在 "widget.cpp" 文件中重写 keyPressEvent() 虚函数


3.2 组合按键

在 Qt 助手中搜索:Qt::KeyboardModifier,如下图示:

        Qt::KeyboardModifier 中定义了在处理键盘事件时对应的修改键。在 Qt 中,键盘事件可以与修改键以起使用,以实现一些复杂的交互操作。KeyboardModifier 中修改键的具体描述如下:

示例:


4. 鼠标事件

        在 Qt 中,鼠标事件是用 QMouseEvent 类来实现的。当在窗口中按下鼠标或者移动鼠标时,都会产生鼠标事件。

        利用 QMouseEvent 类可以获取鼠标的哪个键被按下了以及鼠标的当前位置等信息。在 Qt 帮助文档中查找 QMouseEvent 类如下图示:


4.1 鼠标单击事件

        在 Qt 中,鼠标按下是通过虚函数 mousePressEvent() 来捕获的。mousePressEvent() 函数原型如下:

[ virtual protected] void QWidget:: mousePressEvent (QMouseEvent * event )

鼠标左右键及滚的表示如下:

  • Qt::LeftButton 鼠标左键
  • Qt::RightButton 鼠标右键
  • Qt::MidButton 鼠标滚轮

鼠标左键,操作演示:

1. 在 "widget.h" 头文件中声明鼠标按下事件

 


2. 在 "widget.cpp" 文件中重新实现 mousePressEvent() 函数

实现效果如下:


鼠标右键,操作演示:

实现效果如下:


鼠标滚轮,操作演示:

实现效果如下:


4.2 鼠标释放事件

        鼠标释放事件是通过虚函数 mouseReleaseEvent() 来捕获的。mouseReleaseEvent() 函数原型如下:

[ virtual protected] void QWidget:: mouseReleaseEvent (QMouseEvent * event )

示例:

执行效果如下:


4.3 鼠标双击事件

        鼠标双击事件是通过虚函数:mouseDoubleClickEvent() 来实现的。mouseDoubleClickEvent() 函数原型如下:

[ virtual protected] void QWidget:: mouseDoubleClickEvent (QMouseEvent * event )

示例:鼠标左键双击

执行效果如下:


4.4 鼠标移动事件

        鼠标移动事件是通过虚函数:mouseMoveEvent() 来实现的。同时为了实时捕获鼠标位置信息,需要通过函数 setMouseTracking() 来追踪鼠标的位置。mouseMoveEvent()函数原型如下:

[ virtual protected] void QWidget:: mouseMoveEvent (QMouseEvent * event )

setMouseTracking() 函数原型如下:

void setMouseTracking( bool enable )

        说明:setMouseTracking() 函数默认是 false,需要设置为 true,才能实时捕获鼠标位置信息。否则只有当鼠标按下时才能捕获其位置信息。

示例:

执行效果:


4.5 滚轮事件

        在 Qt 中,鼠标滚轮事件是通过 QWheelEvent 类来实现的。滚轮滑动的距离可以通过 delta() 函数获取。delta() 函数原型如下:

int QGraphicsSceneWheelEvent:: delta() const

        其中返回值代表滚轮滑动的距离。正数表示滚轮相对于用户向前滑动,负数表示滚轮相对于用户向后滑动。

示例:

执行效果如下:


5. 定时器

        Qt 中在进行窗口程序的处理过程中,经常要周期性的执行某些操作,或者制作一些动画效果,使用定时器就可以实现。所谓定时器就是在间隔一定时间后,去执行某一个任务。定时器在很多场景下都会使用到,如弹窗自动关闭之类的功能等。

Qt 中的定时器分为 QTimerEvent 和 QTimer 这 2 个类。

  • QTimerEvent 类用来描述一个定时器事件。在使用时需要通过 startTimer() 函数来开启⼀个定时器,这个函数需要输入一个以毫秒为单位的整数作为参数来表明设定的时间,它返回的整型值代表这个定时器。当定时器溢出时(即定时时间到达)就可以在 timerEvent() 函数中获取该定时器的编号来进行相关操作。
  • QTimer 类来实现一个定时器,它提供了更高层次的编程接口,如:可以使用信号和槽,还可以设置只运行一次的定时器。

5.1 QTimerEvent 类

示例 1:在 UI 界面上放置一个 LCD Number 控件,让其 10 秒数字不断递减到 0,类似倒计时。

1. 新建项目,在 UI 界面文件放置一个 LCD Number 控件


2. 在 "widget.h" 头文件中声明 timerEvent() 函数,并定义一个整型变量


3. 在 "widget.cpp" 文件中重写 timerEvent() 函数

实现效果如下:


5.2 QTimer 类

        示例:在 UI 界面放置一个 Label 标签,两个按钮,分别是 “开始” 和 “停止” ,当点击 “开始” 按钮时,开始每隔 1 秒计数一次,点击 “停止” 按钮时,暂停计数。

1. 设计 UI 界面


2. 在 "widget.cpp" 文件中实现对应功能

实现效果如下:


示例:获取系统日期及时间

在 Qt 中,获取系统的日期及实时时间可以通过 QTimer 类和 QDateTime 类。

        QDateTime 类提供了字符串格式的时间。字符串形式的时间输出格式由 toString() 方法中的 format 参数列表决定,可⽤的参数列表如下:

1. 设计 UI 界面文件

放置一个 Label 控件,用来显示日期及时间,放置两个按钮:“开始” 和 “停止” 


在 "widget.h" 头文件中声明更新时间的槽函数


在 "widget.cpp" 文件中实现对应功能

实现效果如下:


6. 事件分发器

事件分发器概述:

        在 Qt 中,事件分发器(Event Dispatcher)是一个核心概念,用于处理 GUI 应用程序中的事件。事件分发器负责将事件从一个对象传递到另一个对象,直到事件被处理或被取消。每个继承自 QObject 类或 QObject 类本身都可以在本类中重写 bool event(QEvent *e) 函数,来实现相关事件的捕获和拦截。

事件分发器工作原理:

        在 Qt 中,我们发送的事件都是传给了 QObject 对象,更具体点是传给了 QObject 对象的 event() 函数。所有的事件都会进入到这个函数里面,那么我们处理事件就要重写这个 event() 函数。event() 函数本身不会去处理事件,而是根据 事件类型(type值)调用不同的事件处理函数。事件分发器就是工作在应⽤程序向下分发事件的过程中,如下图:

        如上图,事件分发器用于分发事件。在此过程中,事件分发器也可以做拦截操作。事件分发器主要是通过 bool event(QEvent *e) 函数来实现。其返回值为布尔类型,若为 ture,代表拦截,不向下分发。

        Qt 中的事件是封装在 QEvent类 中,在 Qt 助手中输入 QEvent 可以查看其所包括的事件类型,如下图示:

示例:

在 "widget.h" 头文件中声明鼠标点击事件和事件分发器

如下图示:


在 "widget.cpp" 文件中实现鼠标点击事件和拦截事件


7. 事件过滤器

        在 Qt 中,一个对象可能经常要查看或拦截另外一个对象的事件,如对话框想要拦截按键事件,不让别的组件接收到,或者修改按键的默认值等。通过上面的学习,我们已经知道,Qt 创建了 QEvent 事件对象之后,会调用 QObject 的 event() 函数 处理事件的分发。显然,我们可以在 event() 函数中实现拦截的操作。由于 event() 函数是 protected 的,因此,需要继承已有类。如果组件很多,就需要重写很多个 event() 函数。这当然相当⿇烦,更不用说重写 event() 函数还得小心一堆问题。好在 Qt 提供了另外一种机制来达到这一目的:事件过滤器。

事件过滤器是在应用程序分发到 event 事件分发器 之前,再做一次更高级的拦截。

如下图示:

事件过滤器的一般使用步骤:

  1. 安装事件过滤器;
  2. 重写事件过滤器函数:eventfilter() 。

示例:

(1)新建 Qt 项目

基类选择 QWidget,同时勾选 UI 界面文件,如下图示:


(2)设计 UI 文件


(3)在项目新添加⼀个类:MyLabel

先选中项目名称 QEvent,点击鼠标右键,选择 add new ... ,弹出如下对话框:


(4)选择:Choose ...

弹出如下界面:


(5)此时项目中会新添加以下两个文件


(6)在 UI 文件中选中 Label,右键 ——> 提升为...


(7)当点击 "提升为... " 之后,弹出对话框


(8)在 "mylabel.h" 中声明鼠标点击事件和事件分发器


(9)在 "mylabel.cpp" 文件中实现鼠标点击事件和事件分发器


(10)在 "widget.h" 头文件中声明事件过滤器函数


(11)在 "widget.cpp" 文件中实现事件过滤器的两个步骤

执行结果如下所示:


本篇完。

下一篇是Qt开发⑩Qt的文件操作+Qt多线程_使用示例。

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

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

相关文章

【含文档+PPT+源码】基于过滤协同算法的旅游推荐管理系统设计与实现

项目介绍 本课程演示的是一款基于过滤协同算法的旅游推荐管理系统设计与实现,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含:项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系…

华为AP 4050DN-HD的FIT AP模式改为FAT AP,家用FAT基本配置

在某鱼买了两台华为AP 4050DN-HD , AP是二手的 , 在AC上上过线 , 所以就不能开机自选为FIP模式了 我没有AC无线控制器 , 就是买一个自己玩 , AP又是FIT瘦AP模式 ,所以我就想把AP的瘦AP模式改为FAT胖AP模式 1. 准备工作 1.1下载好对应软件,进入到 企业业务网站去下…

智慧校园平台在学生学习与生活中的应用

随着科技的发展,教育领域也在不断探索新的模式与方法。智慧校园平台作为教育信息化的重要组成部分,正逐渐成为推动教育改革、提高教学质量的关键工具。 一.智慧校园平台概述 智慧校园平台是一种集成了教学管理、资源服务、数据分析等多功能于一体的数字…

【软考-架构】备战2025软考

新老教材对比 科目1(信息系统综合)考点详解 科目2(系统架构设计案例)考点详解 科目3(系统架构设计论文)考点详解 趋于越来越具体 学习方法推荐 第一阶段 – 基础知识阶段 建议一个半月; 先过…

Github更新本地仓库到远程总是失败文件过大,如何解决。

环境: AI-Sphere-Butler 问题描述: Github更新本地仓库到远程总是失败文件过大,如何解决。 解决方案: 问题核心在于 历史提交中仍然存在未被 LFS 正确追踪的大文件。 终极解决方案 (必须按顺序执行) 第一步:修…

IP-----动态路由OSPF(2)

这只是IP的其中一块内容,IP还有更多内容可以查看IP专栏,前一章内容为动态路由OSPF ,可通过以下路径查看IP-----动态路由OSPF-CSDN博客,欢迎指正 注意!!!本部分内容较多所以分成了两部分在上一章 5.动态路…

Git系列之-工作区回滚

目录 前言 Git回滚工作区的代码 回滚暂存区的代码 回滚Commit本地分支后的代码 git push把修改提交到远程仓库 归属系列: 前言 本文旨在描述Git中各种回退操作。 Git回滚工作区的代码 前提:当前工作区未进行暂存操作。 git checkout -- a.txt …

汽车悬架系统技术演进:从被动到全主动的革新之路(主动悬架类型对比)

在汽车工业的百年发展史中,悬架系统始终是平衡车辆性能与舒适性的关键战场。随着消费者对驾乘体验要求的不断提升,传统被动悬架已难以满足中高端车型的需求,而半主动与全主动悬架技术的崛起,正在重塑行业格局。本文将深入解析三大…

快速理解Spring 和 Spring Boot 的核心区别

1. 定位与目标 Spring Framework 定位:一个以解耦和模块化为核心的企业级 Java 开发框架,提供 IOC(控制反转)、AOP(面向切面编程) 等基础功能。解决的问题:通过依赖注入和模块化设计简化复杂的企…

【JavaSE-1】初识Java

1、Java 是什么? Java 是一种优秀的程序设计语言,人类和计算机之间的交流可以借助 Java 这种语言来进行交流,就像人与人之间可以用中文、英语,日语等进行交流一样。 Java 和 JavaScript 两者有关系吗? 一点都没有关系!!! 前端内容:HTML CSS JS,称为网页三剑客 2、JDK 下…

【新手入门】SQL注入之盲注

一、引言 在我们的注入语句被带入数据库查询但却什么都没有返回的情况我们该怎么办? 例如应用程序返回到一个"通用的"的页面,或者重定向一个通用页面(可能为网站首页)。这时,我们之前学习的SQL注入的办法就无法使用了。这种情况我们称之为无…

docker本地镜像源搭建

最近Deepseek大火后,接到任务就是帮客户装Dify,每次都头大,因为docker源不能用,实在没办法,只好自己搭要给本地源。话不多说具体如下: 1、更改docker的配置文件,添加自己的私库地址&#xff0c…

Sqlserver安全篇之_启用TLS即配置SQL Server 数据库引擎以加密连接

官方文档 https://learn.microsoft.com/zh-cn/sql/database-engine/configure-windows/configure-sql-server-encryption?viewsql-server-ver16 https://learn.microsoft.com/zh-cn/sql/database-engine/configure-windows/manage-certificates?viewsql-server-ver15&pre…

Win10环境借助DockerDesktop部署单节点Redis6

Win10环境借助DockerDesktop部署单节点Redis6 前言 在后端和大数据开发中,Redis是非常常见的一个组件,常用作KV键值对存储及分布式锁或缓存加速。 之前笔者使用Win版Redis实现了本地部署: https://lizhiyong.blog.csdn.net/article/detai…

【AIGC系列】3:Stable Diffusion模型原理介绍

目录 1 前言2 基础概念2.1 Latent space2.2 AutoEncoder2.3 VAE2.4 扩散模型2.5 多模态交叉注意力 3 Stable Diffusion原理4 整体框架4.1 文生图4.2 图生图4.3 修复 1 前言 Stable diffusion是一个基于 Latent Diffusion Models(潜在扩散模型,LDMs&…

七、Three.jsPBR材质与纹理贴图

1、PBR材质金属度和粗糙度 1、金属度metalness 金属度属性.metalness表示材质像金属的程度, 非金属材料,如木材或石材,使用0.0,金属使用1.0。 threejs的PBR材质,.metalness默认是0.5,0.0到1.0之间的值可用于生锈的金属外观 new THREE.MeshStandardMaterial({met…

解决npm run dev报错

解决:Node.js 版本更新后与 OpenSSL 不兼容导致的npm报错“Error: error:0308010C:digital envelope routines::unsupported” 方法一:更改系统环境变量方法二:更改项目环境变量方法三:更换 Node.js 版本方法四:升级依…

MySQL零基础教程10—正则表达式搜索(下)

前边已经初步认识了正则表达式,今天继续来看在mysql中使用正则表达式搜索的其他用法 mysql正则表达式的“或” 使用正则表达式可以帮助我们更加灵活地进行“或”条件的数据检索,直接上例子: 场景一:查询教师表中,院…

Hadoop第一课(配置linux系统)

1、让hadoop用户,有root权限,如果可以不输密码更好: (1)先登入root用户 (2)visudo命令进入配置文件 (3)找到 root ALL(ALL) ALL这一行,在该行下面增加:hadoop ALL(ALL) ALL (:set nu可以显示行号&#xff…

量子计算的数学基础:复数、矩阵和线性代数

量子计算是基于量子力学原理的一种新型计算模式,它与经典计算机在信息处理的方式上有着根本性的区别。在量子计算中,信息的最小单位是量子比特(qubit),而不是传统计算中的比特。量子比特的状态是通过量子力学中的数学工具来描述的,因此,理解量子计算的数学基础对于深入学…