Qt·事件处理机制

news2025/1/11 21:00:15

思维导读

一、事件简介

  QT程序是事件驱动的, 程序的每个动作都是由内部某个事件所触发。QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期。

  常见的QT事件类型如下:

 键盘事件: 按键按下和松开

 鼠标事件: 鼠标移动,鼠标按键的按下和松开

 拖放事件: 用鼠标进行拖放

 滚轮事件: 鼠标滚轮滚动

 绘屏事件: 重绘屏幕的某些部分

 定时事件: 定时器到时

 焦点事件: 键盘焦点移动

 进入和离开事件: 鼠标移入widget之内,或是移出

 移动事件: widget的位置改变

 大小改变事件: widget的大小改变

 显示和隐藏事件: widget显示和隐藏

 窗口事件: 窗口是否为当前窗口

  QT将系统产生的消息转化为QT事件,QT事件被封装为对象,所有的QT事件均继承抽象类QEvent,用于描述程序内部或外部发生的动作,任意的QObject对象都具备处理QT事件的能力。

文章最后为大家准备了Qt资料
↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡↡

二、QT事件产生

(1)操作系统事件

  操作系统将获取的事件,比如鼠标按键,键盘按键等keyPressEvent,keyReleaseEvent,mousePressEvent,mouseReleaseEvent事件, 放入系统的消息队列中,Qt事件循环的时候读取消息队列中的消息,转化为QEvent并被分发到相应的QWidget对象,相应的QWidget中的event(QEvent *)进行事件处理会对事件进行处理,event(QEvent *)会根据事件类型调用不同的事件处理函数,在事件处理函数中发送QT预定义的信号,最终调用信号关联的槽函数。

  GUI应用程序的事件处理:

  A、QT事件产生后会被立即发送到相应的QWidget对象

  B、相应的QWidget中的event(QEvent *)进行事件处理

  C、event(QEvent *)根据事件类型调用不同的事件处理函数

  D、在事件处理函数中发送QT预定义的信号

  E、调用信号关联的槽函数

(2)Qt应用程序自己产生

  程序产生事件有两种方式, 一种是调用QApplication::postEvent(), 例如QWidget::update()函数,当需要重新绘制屏幕时,程序调用update()函数,new出来一个paintEvent,调用 QApplication::postEvent(),将其放入Qt的消息队列中,等待依次被处理;

  另一种方式是调用sendEvent()函数,事件不会放入队列, 而是直接被派发和处理, QWidget::repaint()函数用的就是阻塞型的。

 sendEvent()中事件对象的生命期由Qt程序管理,支持分配在栈上和堆上的事件对象;postEvent()中事件对象的生命期由Qt平台管理,只支持分配在堆上的事件对象,事件被处理后由Qt平台销毁。

三、Qt事件处理

(1)事件调度

  事件有两种调度方式,同步和异步。

  Qt的事件循环是异步的,当调用QApplication::exec()时,就进入了事件循环,先处理Qt事件队列中的事件, 直至为空,再处理系统消息队列中的消息, 直至为空, 处理系统消息的时候会产生新的Qt事件, 需要对其再次进行处理。

 调用QApplication::sendEvent的时候, 消息会立即被处理,是同步的。实际上QApplication::sendEvent()是通过调用QApplication::notify(), 直接进入了事件的派发和处理环节。

(2)事件通知、派发

  事件过滤器是Qt中一个独特的事件处理机制, 功能强大而且使用起来灵活方便。通过事件过滤器, 可以让一个对象侦听拦截另外一个对象的事件。事件过滤器实现如下: 在所有Qt对象的基类QObject中有一个类型为QObjectList的成员变量,名字为eventFilters,当某个QObject(A)给另一个QObject(B)安装了事件过滤器后, B会把A的指针保存在eventFilters中。在B处理事件前,会先去检查eventFilters列表, 如果非空, 就先调用列表中对象的eventFilter()函数。一个对象可以给多个对象安装过滤器,一个对象能同时被安装多个过滤器, 在事件到达之后, 事件过滤器以安装次序的反序被调用。事件过滤器函数( eventFilter() ) 返回值是bool型, 如果返回true, 则表示事件已经被处理完毕, Qt将直接返回, 进行下一事件的处理。如果返回false, 事件将接着被送往剩下的事件过滤器或是目标对象进行处理。

  QT中,事件的派发是从 QApplication::notify()开始的, 因为QAppliction也是继承自QObject, 所以先检查QAppliation对象, 如果有事件过滤器安装在qApp上, 先调用事件过滤器,接下来QApplication::notify() 会过滤或合并一些事件(比如失效widget的鼠标事件会被过滤掉, 而同一区域重复的绘图事件会被合并),事件被送到reciver::event()处理。

 在reciver::event()中, 先检查有无事件过滤器安装在reciever上。若有, 则调用之。然后根据QEvent的类型, 调用相应的特定事件处理函数。常见的事件都有特定事件处理函数, 比如:mousePressEvent(), focusOutEvent(), resizeEvent(), paintEvent(), resizeEvent()等等。在实际应用中, 经常需要重载特定事件处理函数处理事件。对于不常见的事件, 没有相对应的特定事件处理函数,如果要处理这些事件, 就需要使用别的办法, 比如重载event() 函数, 或是安装事件过滤器。

(3)事件的转发

  对于某些类别的事件,如果在整个事件的派发过程结束后还没有被处理, 那么这个事件将会向上转发给它的父widget, 直到最顶层窗口。Qt中和事件相关的函数通过两种方式相互通信,一种是QApplication::notify(), QObject::eventFilter(), QObject::event()通过返回bool值来表示是否已处理;另一种是调用QEvent::ignore() 或 QEvent::accept() 对事件进行标识,只用于event()函数和特定事件处理函数之间的沟通,而且只有用在某些类别事件上是有意义的, 这些事件就是上面提到的那些会被转发的事件, 包括: 鼠标, 滚轮, 按键等事件。

(4)事件的处理和过滤

  QT提供了五种不同级别的事件处理和过滤:

 A、重写特定事件处理函数.

 最常见的事件处理办法就是重写mousePressEvent(), keyPressEvent(), paintEvent() 等特定事件处理函数。

  B、重写event()函数.

 重写event()函数时, 需要调用父类的event()函数来处理不需要处理或是不清楚如何处理的事件。

 return QWidget::event(event);

 C、在Qt对象上安装事件过滤器

 安装事件过滤器有两个步骤: (假设要用A来监视过滤B的事件)

 首先调用B的installEventFilter( const QOject *obj ), 以A的指针作为参数,所有发往B的事件都将先由A的eventFilter()处理。然后, A要重写QObject::eventFilter()函数, 在eventFilter() 中对事件进行处理。

 D、给QAppliction对象安装事件过滤器

如果给QApplication对象装上过滤器,那么所有的事件在发往任何其他的过滤器时,都要先经过当前eventFilter()。在QApplication::notify() 中, 是先调用qApp的过滤器, 再对事件进行分析, 以决定是否合并或丢弃。

 E、继承QApplication类,并重载notify()函数

 Qt是用QApplication::notify()函数来分发事件的,要在任何事件过滤器查看任何事件之前先得到这些事件,重写notify()函数是唯一的办法。通常来说事件过滤器更好用一些, 因为不需要去继承QApplication类,而且可以给QApplication对象安装任意个数的事件过滤器。

四、自定义事件和eventFilter示例

class DefineEvent : public QEvent
{
public:
    const static QEvent::Type DefineType = static_cast<QEvent::Type>(QEvent::User + 0xFF);

    explicit DefineEvent(QString data) : QEvent(DefineType)
    {
        m_data = data;
    }

    QString data() {return m_data;}

private:
    QString m_data;
};
#ifndef WIDGET_H
#define WIDGET_H
 
#include <QWidget>
#include <QLineEdit>
#include "StringEvent.h"
#include <QMouseEvent>
#include <QDebug>
#include <QApplication>
 
class Widget : public QWidget
{
    Q_OBJECT
    QLineEdit m_edit;
public:
    Widget(QWidget *parent = 0): QWidget(parent), m_edit(this)
    {
        m_edit.installEventFilter(this);
    }
    bool event(QEvent* evt)
    {
        if( evt->type() == QMouseEvent::MouseButtonDblClick )
        {
            qDebug() << "event: Before sentEvent";
            StringEvent e("D.T.Software");
            QApplication::sendEvent(&m_edit, &e);
            qDebug() << "event: After sentEvent";
        }
        return QWidget::event(evt);
    }
 
    bool eventFilter(QObject* obj, QEvent* evt)
    {
        if( (obj == &m_edit) && (evt->type() == StringEvent::TYPE) )
        {
            StringEvent* se = dynamic_cast<StringEvent*>(evt);
            qDebug() << "Receive: " << se->data();
            m_edit.insert(se->data());
            return true;
        }
 
        return QWidget::eventFilter(obj, evt);
    }
 
    ~Widget()
    {
 
    }
};
 
#endif // WIDGET_H


 自定义事件类型可以使用registerEventType
 QEvent::Type ImageLoadedEvent::evType(){
    if(s_evType == QEvent::None)
    {
        s_evType = (QEvent::Type)registerEventType();
    }
    return s_evType;
}

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

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

相关文章

GPC_UICC Configuration

GPC_UICC Configuration_v2.0.pdf 1 简介 本文档规定了在 ETSI 规范 TS 102 221 [TS 102 221]、TS 102 223 [TS 102 223] 中指定的 UICC 平台上实施 GlobalPlatform 规范的配置要求&#xff0c; TS 102 225 [TS 102 225] 和 TS 102 226 [TS 102 226]。 GlobalPlatform Common …

RK3399平台开发系列讲解(网络篇)DNS协议

🚀返回专栏总目录 文章目录 一、DNS 服务器二、DNS 解析流程三、负载均衡沉淀、分享、成长,让自己和他人都能有所收获!😄 📢DNS 是网络世界的地址簿,可以通过域名查地址,因为域名服务器是按照树状结构组织的,因而域名查找是使用递归的方法,并通过缓存的方式增强性能…

chatgpt赋能Python-python_numpy三角函数

介绍 Python是一种流行的编程语言&#xff0c;可以用于数据科学、机器学习和计算机视觉等领域。其中&#xff0c;numpy是Python中最流行的数值计算库&#xff0c;其主要特点之一是支持各种数学函数。在本文中&#xff0c;我们将关注numpy中的三角函数。 三角函数是数学中的一…

王道操作系统学习 P7-P14

目录 操作系统引导 虚拟机 进程的概念、组成、特征 进程的状态与转换 进程控制 操作系统引导 其实整个的引导过程就是&#xff0c; 从特定主存地址开始&#xff0c;取指令&#xff0c;执行ROM中的引导程序&#xff0c; 将磁盘的主引导记录读入内存&#xff0c;执行磁盘引导…

chatgpt赋能Python-python_penup

Python PenUp: 专业针对绘图需求而设计的Python包 在近几年Python语言的流行性大增&#xff0c;不仅吸引了许多新手开发者&#xff0c;也吸引了许多有经验的工程师&#xff0c;特别是针对绘图领域。Python PenUp 是一个专业针对绘图需求而设计的Python包&#xff0c;可以让工程…

【利用AI让知识体系化】深入浅出Puppeteer

文章目录 1. Puppeteer简介1.1 什么是Puppeteer1.2 它能做什么Puppeteer能够完成以下一些主要的操作&#xff1a;1.3 为什么要使用Puppeteer 2. 安装和配置Puppeteer2.1 安装Puppeteer2.2 配置Puppeteer2.3 第一个Puppeteer程序 3. Puppeteer的基础功能3.1 打开和关闭浏览器3.2…

chatgpt赋能Python-python_pd合并

Python数据分析&#xff1a;探秘pd合并 在Python数据分析的过程中&#xff0c;经常需要对多个数据表进行合并操作以便进行有意义的分析。在Python中&#xff0c;使用pandas库中的merge()函数或者concat()函数可以很容易地完成数据合并。 merge()函数 merge()函数是pandas库中…

shell 脚本命令

文章目录 一.sort命令实验 二.uniq命令命令演示 三.tr命令命令演示 四.cut命令命令演示 五.split命令六.paste命令实验演示 七.eval命令 一.sort命令 以行为单位对文件内容进行排序&#xff0c;也可以根据不同的数据类型来排序比较原则是从首字符向后&#xff0c;依次按ASCII码…

chatgpt赋能Python-python_nonetype

Python Nonetype&#xff1a;什么是Nonetype以及如何处理&#xff1f; 在Python编程中&#xff0c;你可能会遇到NoneType&#xff0c;也就是None类型。如果你不知道NoneType是什么&#xff0c;它可以导致代码中的错误。 什么是NoneType&#xff1f; NoneType表示空值或者没有…

【数据结构】二叉树顺序结构、链式结构的实现、遍历二叉树(前序 中序 后序 层序)

文章目录 1.二叉树结构实现1.1顺序结构的实现1.2链式结构的实现 2.堆的概念和介绍3.二叉树的遍历3.1前序遍历3.2中序遍历3.3后序遍历3.4层序遍历 1.二叉树结构实现 1.1顺序结构的实现 在之前的文章中&#xff0c;我们对二叉树有了一定的了解&#xff0c;这里我们会对二叉树再进…

el-table实现可拖拽移动列和动态排序字段

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f35f;欢迎来到前端初见的博文&#xff0c;本文主要讲解在工作中以一个案例el-table实现可拖拽移动列和动态排序字段&#x1f35f; &#x1f468;‍&#x1f527; 个人主页 : 前端初见 &…

chatgpt赋能Python-python_nanmean

Python的nanmean函数&#xff1a;用于计算数组的平均值 Python引入的nanmean函数是一种快速而有效的计算数组平均值的方法。与其他Python中的平均值函数不同&#xff0c;nanmean函数可以处理NaN值&#xff0c;即缺失值。在数据科学和统计学中&#xff0c;处理缺失值是一个常见…

chatgpt赋能Python-python_nontype

介绍Python中的NoneType: 完整的解释和实例 在Python编程中&#xff0c;有一个特殊的数据类型叫做"NoneType"&#xff0c;它通常被简称为"None"。这个数据类型被用于表示没有值或空值&#xff08;null&#xff09;。在本文中&#xff0c;我们将探索NoneTy…

Spring(五大类注解,对象的三种注入方式及其优缺点)

目录 1.存储 Bean 对象 1.1前置工作:配置扫描路径 1.2添加注解存储 Bean 对象 1.2.1 Controller [控制器存储] 1.2.2 Service&#xff08;服务存储&#xff09; 1.2.3 Repository&#xff08;仓库存储&#xff09; 1.2.4 Component&#xff08;组件存储&#xff09; 1.…

chatgpt赋能Python-python_os怎么用

Python OS模块&#xff1a;让你的文件操作更高效 在Python编程中&#xff0c;文件和文件夹的操作是非常常见的&#xff0c;例如创建、删除、修改、读取等等。这些任务都需要使用操作系统的命令&#xff0c;但是如果每次都手动调用操作系统命令&#xff0c;这样会使编程效率低下…

Vulkan Tutorial 2 presentation

目录 5 窗口表面 6 交换链 7 图像视图 5 窗口表面 由于Vulkan是一个与平台无关的API&#xff0c;它自己不能直接与窗口系统对接。为了在Vulkan和窗口系统之间建立连接&#xff0c;将结果呈现在屏幕上&#xff0c;我们需要使用WSI&#xff08;窗口系统集成&#xff09;扩展。…

【瑞萨RA_FSP】DMAC/DTC——直接存储器访问与数据传输

文章目录 一、DMAC和DTC模块简介1. DMAC 特性2. DTC 特性 二、DMAC 模块框图分析三、DMAC 传输模式1. 正常传输模式2. 重复传输模式3. 块传输模式4. 重复-块传输模式 四、DTC 模块框图分析五、DTC 传输模式1. 正常传输模式2. 重复传输模式3. 块传输模式 六、DMAC和DTC关键特性对…

WMS 概述 -- “窗口管理员“

WMS 概述 -- "窗口管理员" 1、WMS 职责2、涉及元素3、WMS、AMS与Activity间的关系 1、WMS 职责 WMS职责理解窗口管理WMS 是窗口的管理者&#xff0c;它负责窗口的启动、添加和删除&#xff0c;另外窗口的大小和层级也是由WMS 进行管理的。窗口管理的核心成员有 Disp…

结构体总结

目录 1.普通结构体 2.定义结构体并同时建立变量 3.匿名结构体 4.typedef重命名 5.typedef省略结构体名字 6.结构体数组 7.结构体指针 8.结构体嵌套 9.结构体链表&#xff08;头插法&#xff09; 10.结构体中的函数指针 11.结构体的构造函数和初始化列表 1.普通结构体 stru…