【Qt 事件】—— 详解Qt事件处理

目录

 (一)事件介绍 

(二)事件的处理

(三)按键事件 

3.1 单个按键

3.2 组合按键

(四)鼠标事件

4.1 鼠标单击事件

4.2 鼠标释放事件

 4.3 鼠标双击事件

4.4 鼠标移动事件 

4.5 滚轮事件 

(五) 定时器

5.1 QTimerEvent类

5.2 QTimer类

(六)事件分发器 

6.1 概述

6.2 事件分发器工作原理

(七)事件过滤器 

总结


【前情提示】

信号槽:

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

事件非常类似

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

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

⭐️⭐️ 信号槽就是对于事件的进一步封装;事件是信号槽的底层机制.

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

 (一)事件介绍 

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

 常见事件描述:

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

(二)事件的处理

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

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

示例如下:

  •  1、新建Qt项⽬,基类选择QWidget,同时勾选UI界⾯⽂件,如下图示:

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

 

  • 3、在项目中新添加⼀个类:MyLabel; 先选中项目名称QEvent,点击⿏标右键,选择addnew...,弹出如下对话框: 

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

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

  • 6、在帮助文档中查找对应的内容; 

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

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

  •  9、重写enterEvent()⽅法;

  •  10、在UI文件中选中Label,右键------>提升为...

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

  •  12、修改基类:

  •  13、执行效果如下:当鼠标进入设计好的标签之后,就会在应用程序输出栏中打印:鼠标进入(同理鼠标离开也是一样)


示例2:鼠标左键点击时,打印对应的坐标值;鼠标右键点击时,打印基于屏幕的坐标,点击完毕显示释放操作

  •  1、在上述示例的基础上,在mylabel.h中声明mousePressEvent()⽅法;
//当⿏标点击时,获取对应的坐标值
void mousePressEvent(QMouseEvent *event);
//鼠标释放操作
void mouseReleaseEvent(QMouseEvent *event);
  •  2、在mylabel.cpp中重写mousePressEvent()⽅法;
void mylabel::mousePressEvent(QMouseEvent *event)
{//按下右键if(event->button() == Qt::RightButton){//基于globalqDebug() << "鼠标右键已经按下 x = "<<event->globalX();qDebug() << "鼠标右键已经按下 x = "<<event->globalY();}//按下左键if(event->button() == Qt::LeftButton){//基于窗口的坐标qDebug() << "鼠标左键已经按下 x = "<<event->x();qDebug() << "鼠标左键已经按下 x = "<<event->y();}//按下中间键if(event->button() == Qt::MidButton){qDebug() << "鼠标已经按下 x = "<<event->x();qDebug() << "鼠标已经按下 x = "<<event->y();}
}void mylabel::mouseReleaseEvent(QMouseEvent *event)
{if(event->button() == Qt::LeftButton){qDebug() << "左键被释放";}else if(event->button() == Qt::RightButton){qDebug() << "右键被释放";}else if(event->button() == Qt::MidButton){qDebug() << "中键被释放";}
}

 实现效果如下:


(三)按键事件 

在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框架中,处理鼠标事件是创建交互式图形用户界面的关键部分。鼠标事件包括鼠标点击、双击、移动、滚轮滚动等。这些事件由QMouseEvent类表示,它提供了关于鼠标事件的详细信息,如鼠标位置、按钮状态等。

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

 


鼠标单击和释放操作代码在上述已经完成,下述就不在展示代码!!

4.1 鼠标单击事件

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

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

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

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

4.2 鼠标释放事件

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

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

 4.3 鼠标双击事件

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

[virtual protected] void QWidget::mouseDoubleClickEvent(QMouseEvent *event)
void mylabel::mouseDoubleClickEvent(QMouseEvent *event)
{if(event->button() == Qt::LeftButton){qDebug() << "左键被双击";}else if(event->button() == Qt::RightButton){qDebug() << "右键被双击";}else if(event->button() == Qt::MidButton){qDebug() << "中键被双击";}
}

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
  • 其中返回值代表滚轮滑动的距离。正数表示滚轮相对于用户向前滑动,负数表示滚轮相对于用户向后滑动。
void Widget::wheelEvent(QWheelEvent *event)
{//滚轮事件static int x = 0;x += event->delta();if(event->delta() > 0){qDebug() << "滚轮向前移动了" << x;}else if(event->delta() < 0){qDebug() << "滚轮向后移动了" << x;}
}

执行效果如下: 


(五) 定时器

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

Qt中的定时器分为QTimerEventQTimer这2个类。

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

5.1 QTimerEvent类

示例:在UI界⾯上放置控件,程序启动开始倒计时操作

void Widget::timerEvent(QTimerEvent *event)
{//先判定触发的是否为想要触发的if(event->timerId() != this->timerid){return;}int value = ui->lcdNumber->intValue();if(value <= 0){//停止定时器this->killTimer(this->timerid);return;}value -= 1;ui->lcdNumber->display(value);
}

 实现效果如下:

 


5.2 QTimer类

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

    ui->setupUi(this);QTimer *time = new QTimer(this);connect(ui->btn1 , &QPushButton::clicked,[=](){time->start(1000);});connect(time , &QTimer::timeout,[=](){static int num = 1;ui->label->setText(QString::number (num++));});connect(ui->btn2 , &QPushButton::clicked,[=](){time->stop();});

 实现效果如下:


(六)事件分发器 

6.1 概述

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

6.2 事件分发器工作原理

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

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

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

示例:

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

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

 

 执行结果如下:


(七)事件过滤器 

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

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

 

事件过滤器的⼀般使⽤步骤:

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

示例如下:

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

 

  • 2、设计UI⽂件,如下图; 

  • 3、在项目新添加⼀个类:MyLabel; 先选中项名目称QEvent,点击⿏标右键,选择addnew...,弹出如下对话框: 

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

  • 5、此时项目中会新添加以下两个文件;在UI文件中选中Label,右键------>提升为... 

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

  • 7、在mylabel.h中声明鼠标点击事件和事件分发器; 

  • 8、在mylabel.cpp⽂件中实现鼠标点击事件和事件分发器; 

  • 9、在widget.h头文件中声明事件过滤器函数; 

  • 10、在widget.cpp⽂件中实现事件过滤器的两个步骤;

 执行结果如下:


总结

Qt的事件处理机制非常灵活,通过事件循环、事件对象、信号与槽机制以及事件过滤器,可以高效地处理各种用户交互和系统事件。理解这些概念对于开发复杂的Qt应用程序至关重要。

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

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

相关文章

101.SAP MII功能详解(15)Workbench-Transaction Logic(Iterator)

目录 1.Logic->Iterator 2.演示 配置连接 Iterator使用示例 1.Logic->Iterator 您可以使用此操作迭代循环浏览List&#xff0c;迭代是指遍历某个List数据结构&#xff0c;逐个访问其元素的过程。迭代使用的场景不多。 2.演示 配置连接 Iterator使用示例 数据源是Lis…

Qt:玩转QPainter序列九(文本,文本框,填充)

前言 继续承接序列八 正文 1. drawImage系列函数 绘制图像 inline void drawImage(const QPoint &p, const QImage &image); 作用: 在指定的点 p 上绘制 QImage 图像。图像的左上角将对齐到 p 点。 inline void drawImage(int x, int y, const QImage &image,…

[001-07-001].Redis7缓存双写一致性之更新策略探讨

1、面试题&#xff1a; 1.只要使用缓存&#xff0c;就可能会涉及到redis缓存与数据库双存储双写&#xff0c;只要是双写&#xff0c;就存在数据一致性问题&#xff0c;那么是如何解决数据一致性问题的2.双写一致性&#xff0c;你先动缓存redis还是数据库MySQL&#xff0c;哪一个…

新能源汽车超级电容和电池能量管理系统的simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 电池模型 4.2 电池荷电状态&#xff08;SOC&#xff09;估算 4.3 超级电容器模型 4.4 能量管理 5.完整工程文件 1.课题概述 新能源汽车的能量管理系统&#xff08;Energy Management System, EMS…

中国艺术孙溟㠭凿篆《无用之用》

孙溟㠭凿篆作品《无用之用》 这方作品是孙溟㠭先生用凿木的方式凿刻出来的&#xff0c;呈现出了凿痕的效果&#xff0c;与众不同。 孙溟㠭凿篆《无用之用》 孙溟㠭凿篆《无用之用》 万般皆有所用&#xff0c;取其长补余短&#xff0c;无用之用是为大用&#xff0…

JS实现高度不等的列表虚拟滚动加载

当我们拿到后台返回的1万条数据展示时&#xff0c;如果完全渲染不仅渲染的时间很长&#xff0c;也会导致浏览器性能变差&#xff0c;使用过程中还可能会导致卡顿&#xff0c;使用体验变差。 就需要我们想办法优化这种情况&#xff0c;这个时候使用虚拟滚动加载就能很好的避免这…

ESXi服务器无法安装Windows11:“不符合此版本的Windows所需最低系统要求“

目录 一、问题描述1.使用环境2.问题截图3.问题解析 二、解决方法Ⅰ1.按 ShiftF10 弹出命令提示符2.在弹出的Dos框中输入regedit&#xff0c;回车&#xff0c;进入注册表。3.打开HKEY_LOCAL_MACHINE\SYSTEM\Setup&#xff0c;并新建 LabConfig 的项&#xff0c;在 LabConfig 下创…

SAP 查询中间表

可以看到如下代码中&#xff0c;查询了底表zdbconn&#xff0c;又查了中间表ZTFI0072 DATA: gv_dbs(20) ,go_exc_ref TYPE REF TO cx_sy_native_sql_error,gv_error_text TYPE string,lv_count TYPE syst_index.SELECT SINGLE conntxtFROM zdbconn INTO gv_dbsWHERE sy…

RK3568 Android 11 蓝牙BluetoothA2dpSink 获取用于生成频谱的PCM

Android 中的 A2DP Sink A2DP Sink 在 Android 系统中主要用于 接收 其他蓝牙设备&#xff08;如手机、平板、电脑等&#xff09;发送过来的 高质量的立体声音频。简单来说&#xff0c;它让你的 Android 设备可以充当一个 蓝牙音箱 或 耳机 的角色。 核心功能&#xff1a; 接…

【Java】SpringBoot 单体项目创建 与 整合 Mybatis-Plus

文章目录 前言1. 创建项目与整合MP1.1 IDEA创建SpringBoot项目1.2 SpringBoot整合Mybatis-Plus 2. 远程仓库2.1 创建远程仓库/本地仓库2.2 Add/Commit/Push/Pull 3. 总结与补充3.1 解决refusing to merge unrelated histories3.2 总结3.3 结语 参考资料 SpringBoot 单体项目创建…

Hadoop环境搭建

一、Linux环境准备 Linux命令查询https://www.linuxcool.com/ http://linux.51yip.com/ 安装Linux虚拟机 安装 sudo apt install open-vm-tools 安装 sudo apt install open-vm-tools-desktop &#xff08;可选&#xff09;换国内源 ​​ sudo apt update 更新软件列表&…

火焰传感器详解(STM32)

目录 一、介绍 二、传感器原理 1.原理图 2.引脚描述 三、程序设计 main.c文件 IR.h文件 IR.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 火焰传感器是一种常用于检测火焰或特定波长&#xff08;760nm-1100nm&#xff09;红外光的传感器。探测角度60左右&am…

Docker占用根目录/存储空间过多如何清理?

问题背景 使用df -h查看磁盘空间时发现根目录空间不多了&#xff0c;已使用96%&#xff0c;红色警告&#xff01;&#xff01;&#xff01; 于是使用df -h /* 一层一层定位&#xff0c;终于找到了一个大文件 9G多的文件夹&#xff0c;位置是&#xff1a; /var/lib/docker/o…

无线通信-WIFI通信

文章目录 1. 基础知识2. 工作模式3. AT指令4. 常用AT指令实例5. 连接原子云6. 使用usb转ttl模块测试ATK-MW8266D7. 使用STM32F103ZET6战舰开发板透传模式8. 使用STM32F103ZET6战舰板连接原子云 1. 基础知识 ATK-ESP-01 ATK-ESP-01模块支持标准的IEEE802.11b/g/n协议&#xff0c…

【Linux】文件魔法师:时间与日历的解密

欢迎来到 CILMY23 的博客 &#x1f3c6;本篇主题为&#xff1a;文件魔法师&#xff1a;时间与日历的解密 &#x1f3c6;个人主页&#xff1a;CILMY23-CSDN博客 &#x1f3c6;系列专栏&#xff1a;Python | C | C语言 | 数据结构与算法 | 贪心算法 | Linux | 算法专题 | 代码…

【uniapp重大bug】uni-data-select的localdata改变,也会触发@change方法

bug描述 uni-data-select的下拉列表值localdata是动态获取的&#xff0c;且绑定了change方法&#xff0c;在页面加载后&#xff0c;请求localdata的列表数据&#xff0c;给localdata重新赋值&#xff0c;此时发现自动触发了change方法 当前uni版本&#xff1a;^2.0.2-30709202…

Axure RP10安装教程(Pro版)

下载链接 https://ga90eobypbb.feishu.cn/docx/UyzSd4q8SoXySjxtrcac4QnVn3f Axure RP 是一款专业的快速原型设计工具。它能帮助用户高效地创建网页和移动应用的线框图、流程图、原型和规格说明文档。拥有丰富的交互组件&#xff0c;可模拟各种复杂交互效果&#xff0c;如点击…

【千帆AppBuilder】使用Python调用基于官方的API创建图片故事的应用,一起体验下全代码模式下是怎样的效果

欢迎来到《小5讲堂》 这是《千帆》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景基本信息名称简介角色指令 能力扩展组件对话开场白推荐问 模型选…

98.SAP MII功能详解(12)Workbench-Transaction Logic(For Next Loop)

目录 1.Logic->For Next Loop 2.演示 配置对象 配置连接 for循环的整体演示 1.Logic->For Next Loop 此操作用于在预定义的次数内执行任务。每次迭代都会执行直接跟随For Next循环操作的所有操作&#xff0c;直到达到To限制。 若要在达到To属性限制之前停止&…

旅行追踪和行程规划工具AdventureLog

什么是 AdventureLog &#xff1f; AdventureLog 是一种记录您的旅行并与世界分享的简单方法。您可以在日志中添加照片、笔记等。跟踪您访问过的国家、探索去过的地区和地方。您还可以查看您的旅行统计数据和里程碑。AdventureLog 旨在成为您终极的旅行伴侣&#xff0c;帮助您记…