Qt 系统相关 - 事件

news2025/1/10 21:50:46

目录

1. 事件介绍

2. 事件的处理

示例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 类

5.3 获取系统日期及时间

6. 事件分发器

6.1 概述

6.2 事件分发器工作原理

​编辑7. 事件过滤器


1. 事件介绍

        前面我们学习了信号槽,它是用户进行的各种操作,可能会产生出信号,程序员给某个信号指定槽函数,当信号触发时,就能够自动的执行到对应的槽函数。事件和信号槽非常类似,用户进行的各种操作,也会产生事件。程序员同样可以给事件关联上处理函数(处理的逻辑),当事件触发的时候,就能够执行到对应的代码。

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

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

常见事件描述:

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

2. 事件的处理

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

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


示例1:处理鼠标进入和离开

1、新建 Qt 项目,基类选择 QWidget,同时勾选 UI 界面文件,如下图示;

2、设计 UI 文件,如下图示;

3、这里需要创建 QLabel 的子类,重写 enterEvent 和 leaveEvent,在项目中新添加一个类:MyLabel;

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

4、选择:Choose .... ,弹出如下界面:

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

6、要想重写父类的函数,就需要确保你这边写的函数名字和函数的参数列表都完全一致(形参名无所谓),为了防止单词拼写错误,我们可以在帮助文档中查找对应的内容;

7、点击 "显示" 之后,出现如下内容:

8、复制 enterEvent() 和 leaveEvent() ,粘贴在项目文件 "mylabel.h" 中;

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

10、上述代码,虽然重写了这俩函数,但是还是有点问题。运行程序,我们会发现鼠标进入和移出界面上没有一点反应。这是因为当前在界面上创建的这个 label 其实是 QLabel,不是咋们自己写的 Label,咋们必须要确保界面上的这个 label 是一个咋们自己定义的 Label 类的实例,程序才会执行到。解决办法也很简单,在 UI 文件中选中 Label,右键 ------> 提升为...

11、当点击 "提升为... " 之后,弹出如下对话框:

12、修改基类:

13、执行效果如下:当鼠标进入设计好的标签之后,就会在应用程序输出栏中打印:鼠标进入


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

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

        mousePressEvent 这个函数,按下左键、右键、滚轮都能触发,有的鼠标还带有前进后退侧键,也是可以触发的;但是还有的鼠标,有着更多的按键,这就不一定能触发了~

1、在上述示例的基础上,在 mylabel.h 中声明 mousePressEvent() 方法;

2、在 mylabel.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 中修改键的具体描述如下:

Qt::NoModifier无修改键
Qt::ShiftModifierShift 键
Qt::ControlModifierCtrl 键
Qt::AltModifierAlt 键
Qt::MetaModifierMeta键(在Windows上指Windows键,在macOS上指Command键)
Qt::KeypadModifier使用键盘上的数字键盘进行输⼊时,Num Lock键处于打开状态
Qt::GroupSwitchModifier用于在输入法 组之间 切换

示例:

实现效果如下:

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)


示例:鼠标左键释放

1、在 "widget.h" 头文件中声明鼠标释放事件;

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

 实现效果如下:

4.3 鼠标双击事件

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

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


示例:鼠标左键双击

1、在 "widget.h" 头文件中声明鼠标双击事件;

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

 实现效果如下:

4.4 鼠标移动事件

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

mouseMoveEvent()函数原型如下:

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

setMouseTracking()函数原型如下:

  • void setMouseTracking(bool enable)

说明:

        鼠标移动不同于鼠标按下。随便移动一下鼠标,就会产生出大量的鼠标移动事件。当你进行捕获事件的时候,尤其是在这里在进行一些复杂逻辑的时候,程序负担就很重,很容易产生卡顿之类的情况。

        Qt 为了保证程序的流畅性,默认情况下不会对鼠标移动进行追踪,鼠标移动的时候不会调用 mouseMoveEvent。除非显示告诉 Qt 要追踪鼠标位置。

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


示例:

1、在 "widget.h" 头文件中声明鼠标移动事件;

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

 执行效果:

4.5 滚轮事件

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

int QGraphicsSceneWheelEvent::delta() const

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


示例:

1、在 "widget.h" 头文件中声明鼠标滚轮事件;

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

执行效果:

5. 定时器

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

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

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

5.1 QTimerEvent 类

示例1:在UI界面上放置两个 Label 控件,⼀个让其1秒数字累加⼀次,⼀个让其2秒数字累加⼀次

1、新建项目,在UI界面文件放置两个 Label 控件;

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

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

实现效果如下:

5.2 QTimer 类

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

1、设计 UI 界面如下:

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

实现效果如下:

5.3 获取系统日期及时间

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

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


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

1、设计UI界面文件;放置⼀个 Label控件,用来显示日期及时间,放置两个按钮:"开始" 和 "停止" ;

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

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

实现效果如下:

6. 事件分发器

6.1 概述

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

6.2 事件分发器工作原理

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

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

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


示例:

1、在 "widget.h" 头文件中声明 鼠标点击事件 和 事件分发器;如下图示:

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

执行结果如下:

7. 事件过滤器

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

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

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

  • 安装事件过滤器;
  • 重写事件过滤器函数: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" 文件中实现事件过滤器的两个步骤;

执行结果如下所示:

 

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

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

相关文章

一篇文章了解上位机软件架构

软件架构 上位机基本软件架构**UI层****业务层(承上启下)****驱动层** 上位机基本软件架构 基本上所有软件都可以分为三层结构进行设计,ui界面层,中间业务逻辑层,驱动层,各个层级之间相互联系,…

汇编编译环境的安装

目录 1. 下载安装包 1.1 迅雷下载链接 1.2 Gitee下载 2. 安装 1. 下载安装包 1.1 迅雷下载链接 迅雷云盘迅雷云盘https://pan.xunlei.com/s/VO4AFFTT3ls2zGSOvFOLSP_mA1?pwdkmeh# 1.2 Gitee下载 assembler language: assembler languagehttps://gitee.com/Axurea/asse…

软考高级:数据库设计中,属性冲突、命名冲突、结构冲突

在数据库设计中,属性冲突、命名冲突和结构冲突是常见的问题,它们主要涉及不同数据源或表之间的数据整合和管理。下面我们通过通俗易懂的例子和解释来理解这些概念。 通俗示例 想象你有两家书店,它们各自维护一份图书的库存记录。 属性冲突…

高质量翻译对中国开发者提高游戏用户参与度的影响

随着中国游戏开发商继续向全球市场扩张,用户参与度成为其游戏成功的关键因素。在竞争激烈的行业中,玩家有无数选择可供选择,保持用户参与对于维持游戏的流行和增长至关重要。高质量的翻译在这一过程中起着至关重要的作用,确保游戏…

动力电池制造行业RFID产品应用方案

在全球能源转型的大背景下,新能源汽车产业蓬勃发展,动力电池作为其核心部件,其性能和质量至关重要。然而,当前国内上百家动力电池生产企业在自动化和信息化方面存在诸多不足,严重制约了行业的发展。实现动力电池的智能…

邦德创意研发的果皮咖啡,让喝咖啡也能有喝奶茶的满足感

在当下咖啡饮品市场中,果咖早已不是新鲜事物。它们以各式各样的水果与咖啡的融合,为咖啡爱好者带来新鲜的味觉体验。然而,很多果咖饮品虽色彩斑斓、风味独特,却往往止步于水果和咖啡的直接混合,未能触及更深层次的健康…

使用 onBeforeRouteLeave 组合式函数提升应用的用户体验

title: 使用 onBeforeRouteLeave 组合式函数提升应用的用户体验 date: 2024/8/14 updated: 2024/8/14 author: cmdragon excerpt: 摘要:本文介绍了在Nuxtjs中使用onBeforeRouteLeave组合式函数来提升应用用户体验的方法。onBeforeRouteLeave允许在组件离开当前路…

IDEA 创建类时自动生成注释

一、背景 在开发的过程中,公司都会要求开发针对自己创建的类进行一些描述说明,为了便于程序员在创建类时快速生成注释。 二、如何配置? 打开File -> Settings -> Editor -> File and Code Templates -> Includes,在File Header…

JavaWeb04-MyBatis与Spring结合

目录 前言 一、MyBatis入门(MyBatis官网) 1.1 创建mybatis项目(使用spring项目整合式方法) 1.2 JDBC 1.3 数据库连接池 1.4 实用工具:Lombok 二、MyBatis基础操作 2.1 准备工作 2.2 导入项目并实现操作 2.3 具…

LeetCode 热题 HOT 100 (036/100)【宇宙最简单版】【创作中】

希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持!

Ubuntu(22.04)云主机SSH安全加固

1、新增SSH服务端口 #vim /etc/ssh/sshd_config 找到 #Port 22 去掉注释符,下面添加:Port [新端口] 2、本地防火墙放通 #ufw allow [新端口] #ufw reload //防火墙重新加载 #ufw status verbose //查询是否开放SSH新端口 3、腾讯云防火墙配…

在线预约小程序的设计

管理员账户功能包括:系统首页,个人中心,用户管理,在线预约管理,管理员管理,系统管理 微信端账号功能包括:系统首页,在线预约,我的 开发系统:Windows 架构模…

为何UDP攻击相比常规攻击更易导致服务器瘫痪?

在网络安全领域,UDP(用户数据报协议)攻击因其独特的特性和高效的破坏性而备受关注。与常规的网络攻击相比,UDP攻击往往能够更快地使目标服务器陷入瘫痪状态,这背后的原因值得我们深入探讨。 UDP协议的无连接性是其成为…

Linux--HTTP协议(http服务器构建)

目录 1.HTTP 协议 2.认识 URL 3.urlencode 和 urldecode(编码) urlencode(URL编码) urldecode(URL解码) 4.HTTP 协议请求与响应格式 4.1HTTP 常见方法(三种) 5.HTTP 的状态码…

node速起架子

链接:https://pan.baidu.com/s/1NF1e75P8pNDzphO1jBUSyg 提取码:sf3w 下载node 安装好node -v 配置npm的全局安装路径 使用管理员身份运行命令行,在命令行中,执行如下指令: npm config set prefix "E:\develop\…

【网络】TCP协议通信的重要策略——滑动窗口,快重传,流量控制,拥塞控制,延时应答

目录 MSS值 滑动窗口 滑动窗口与重发机制 快重传机制 滑动窗口与流量控制 滑动窗口与拥塞控制 延时应答 个人主页:东洛的克莱斯韦克-CSDN博客 相关文章 【网络】传输层TCP协议的报头和传输机制-CSDN博客 【网络】详解TCP协议通信时客户/服务端的状态-CSDN博…

「MyBatis」数据库相关操作2

🎇个人主页 🎇所属专栏:Spring 🎇欢迎点赞收藏加关注哦! #{} 和 ${} 我们前面都是采用 #{} 对参数进行赋值,实际上也可以用 ${} 客户端发送⼀条 SQL 给服务器后,大致流程如下: 1.…

图像识别,图片线条检测

import cv2 import numpy as np # 读取图片 img cv2.imread(1.png)# 灰度化 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 边缘检测 edges cv2.Canny(gray, 100, 200) 当某个像素点的梯度强度低于 threshold1 时,该像素点被认为是非边缘;当梯度强度…

代码随想录——无重复字串的最长子串(Leetcode hot8)

题目链接 滑动窗口(双指针) 思路: 初始化: 检查字符串的长度。如果长度为0或1,则直接返回长度,因为这样的字符串本身就是无重复的。初始化两个指针 slow 和 fast,分别代表当前最长无重复子字符串的起始…

Django 数据库迁移:makemigrations 和 migrate 命令详解及常见问题解决

目录 1. 问题所示2. python manage.py makemigrations3. python manage.py migrate4. 拓展 1. 问题所示 最初始的状态是遇到这个问题 由于刚开始跑python web项目,开源项目附带的Readme,个别命令不太懂,对此详细研究其基本知识 最终的解决方…