【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

相关文章

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

idea的终端(Terminal)cmd的命令换成linux的命令详解

《idea的终端(Terminal)cmd的命令换成linux的命令详解》本文介绍IDEA配置Git的步骤:安装Git、修改终端设置并重启IDEA,强调顺序,作为个人经验分享,希望提供参考并支持脚本之... 目录一编程、设置前二、前置条件三、android设置四、设置后总结一、php设置前二、前置条件

python中列表应用和扩展性实用详解

《python中列表应用和扩展性实用详解》文章介绍了Python列表的核心特性:有序数据集合,用[]定义,元素类型可不同,支持迭代、循环、切片,可执行增删改查、排序、推导式及嵌套操作,是常用的数据处理... 目录1、列表定义2、格式3、列表是可迭代对象4、列表的常见操作总结1、列表定义是处理一组有序项目的

python使用try函数详解

《python使用try函数详解》Pythontry语句用于异常处理,支持捕获特定/多种异常、else/final子句确保资源释放,结合with语句自动清理,可自定义异常及嵌套结构,灵活应对错误场景... 目录try 函数的基本语法捕获特定异常捕获多个异常使用 else 子句使用 finally 子句捕获所

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

SQL Server 中的 WITH (NOLOCK) 示例详解

《SQLServer中的WITH(NOLOCK)示例详解》SQLServer中的WITH(NOLOCK)是一种表提示,等同于READUNCOMMITTED隔离级别,允许查询在不获取共享锁的情... 目录SQL Server 中的 WITH (NOLOCK) 详解一、WITH (NOLOCK) 的本质二、工作

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

Java Thread中join方法使用举例详解

《JavaThread中join方法使用举例详解》JavaThread中join()方法主要是让调用改方法的thread完成run方法里面的东西后,在执行join()方法后面的代码,这篇文章主要介绍... 目录前言1.join()方法的定义和作用2.join()方法的三个重载版本3.join()方法的工作原

Spring AI使用tool Calling和MCP的示例详解

《SpringAI使用toolCalling和MCP的示例详解》SpringAI1.0.0.M6引入ToolCalling与MCP协议,提升AI与工具交互的扩展性与标准化,支持信息检索、行动执行等... 目录深入探索 Spring AI聊天接口示例Function CallingMCPSTDIOSSE结束语