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

2024-09-02 06:52
文章标签 详解 qt 事件 事件处理

本文主要是介绍【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应用程序至关重要。

这篇关于【Qt 事件】—— 详解Qt事件处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1129307

相关文章

MySQL数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

MyBatis常用XML语法详解

《MyBatis常用XML语法详解》文章介绍了MyBatis常用XML语法,包括结果映射、查询语句、插入语句、更新语句、删除语句、动态SQL标签以及ehcache.xml文件的使用,感兴趣的朋友跟随小... 目录1、定义结果映射2、查询语句3、插入语句4、更新语句5、删除语句6、动态 SQL 标签7、ehc

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Python版本信息获取方法详解与实战

《Python版本信息获取方法详解与实战》在Python开发中,获取Python版本号是调试、兼容性检查和版本控制的重要基础操作,本文详细介绍了如何使用sys和platform模块获取Python的主... 目录1. python版本号获取基础2. 使用sys模块获取版本信息2.1 sys模块概述2.1.1

一文详解Python如何开发游戏

《一文详解Python如何开发游戏》Python是一种非常流行的编程语言,也可以用来开发游戏模组,:本文主要介绍Python如何开发游戏的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、python简介二、Python 开发 2D 游戏的优劣势优势缺点三、Python 开发 3D

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash

Java中的.close()举例详解

《Java中的.close()举例详解》.close()方法只适用于通过window.open()打开的弹出窗口,对于浏览器的主窗口,如果没有得到用户允许是不能关闭的,:本文主要介绍Java中的.... 目录当你遇到以下三种情况时,一定要记得使用 .close():用法作用举例如何判断代码中的 input