热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

QT框架中事件循环机制及事件分发类详解

在QT框架中,QCoreApplication类作为事件循环的核心组件,为应用程序提供了基础的事件处理机制。该类继承自QObject,负责管理和调度各种事件,确保程序能够响应用户操作和其他系统事件。通过事件循环,QCoreApplication实现了高效的事件分发和处理,使得应用程序能够保持流畅的运行状态。此外,QCoreApplication还提供了多种方法和信号槽机制,方便开发者进行事件的定制和扩展。

一、QT的事件发送类QCoreApplication

QT使用QCoreApplication类为Qt程序提供了事件循环机制。该类继承QObject。QCoreApplication包含主事件循环,来自操作系统的事件(例如计时器和网络事件)和其他事件都将在主事件循环中被处理和调度。

在QT的程序中,主函数一般都是这样的

int main(int argc, char *argv[])
{QApplication a(argc, argv);mainWindow w;w.show();return a.exec();
}

在QT的main函数中,第一句必须定义一个QApplication的对象。QApplication间接继承了QCoreApplication,其对象a调用的是父类QCoreApplication中的exec(),然后进入了主事件循环。

static int QCoreApplication::exec()

主事件循环的生命周期和函数exec的生命周期是相等的,如果主事件循环不退出,那么exec将永远执行,不结束

QCoreApplication中的quit()函数和exit()函数可以使主事件循环退出

static void QCoreApplication::quit()
static void QCoreApplication::exit(int returnCode = 0)

当调用上述两个函数中的任何一个后,QT应用程序的主事件循环退出,并且QT应用程序返回到调用exec的地方,同时exec函数退出并返回对应的退出码,退出码正常值是0,表示正常退出,非0值表示有错误,此外,如果没有主事件循环,那么,调用该函数将不会执行任何动作

QCoreApplication除了提供exec()、quit()和exit()外,还提供了sendEvent()立刻发送事件;postEvent()将事件发布到事件队列中,等待处理;removePostedEvents()将删除事件队列中的所有事件;也可以使用sendPostedEvents()分发事件队列中的所有事件。

 

1.sendEvent

static bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event)

sendEvent()通过notify函数立刻将事件event发送给接受者receiver。返回值由对象的实际事件处理程序决定是true or false,所以,当sendEvent()返回时,事件过滤器或对象本身的事件处理程序已经处理完该事件。sendEvent发送完事件后,并不会删除该事件。 

示例

int main(int argc, char *argv[])
{QApplication a(argc, argv);mainWindow w;QPointF pos;pos.setX(100);pos.setY(100);QMouseEvent event(QEvent::MouseButtonPress, pos, Qt::NoButton, 0, 0);QApplication::sendEvent(w.gettextEdit(), &event);w.show();return a.exec();
}

可见,当运行主函数后,事件马上发送,并通过事件过滤其打印出一条log

 

2.postEvent

static void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority)

postEvent并不会立刻发送事件,而是将事件event添加到事件队列中并立即返回

当QT程序回到主事件循环时,将使用notify()函数将队列中存储的所有事件一起发送。

事件event的对象必须分配在堆上,因为事件的发送队列要在发送后把事件删除,而不能让事件的生命周期自动结束,分配在堆上可以保证事件的生命周期。

事件按优先级从高到低的顺序排序,即优先级高的事件在优先级较低的事件之前排队。优先级介于INT_MAX和INT_MIN之间;有具有相同优先级的事件将按照发布(添加)的顺序进行处理。

事件的优先级在枚举Qt::EventPriority中定义

enum EventPriority {HighEventPriority = 1,//具有此优先级的事件将在具有NormalEventPriority或LowEventPriority的事件之前发送。NormalEventPriority = 0,//具有此优先级的事件在具有HighEventPriority的事件之后但在具有LowEventPriority的事件之前发送。LowEventPriority = -1//具有高优先级的事件在具有HighEventPriority或NormalEventPriority的事件之后发送。
};

优先级示例

enum CustomEventPriority{ImportantEventPriority = Qt::HighEventPriority, // An important eventMoreImportantEventPriority = ImportantEventPriority + 1,// A more important eventCriticalEventPriority = 100 * MoreImportantEventPriority, // A critical eventStatusEventPriority = Qt::LowEventPriority,// Not that importantIdleProcessingDoneEventPriority = StatusEventPriority - 1// These are less important than Status events};

 

3.notify

virtual bool QCoreApplication::notify(QObject *receiver, QEvent *event)

该函数是将事件event发给接受者receiver的实际执行者,返回值由具体的事件处理程序决定,所有事件的发送最终都会调用该函数。

当某些事件发送给接受者后,如果接受者对该事件不感兴趣(比如返回值为false),那么该事件会发给接受者对象的父对象(不是基类或者父类)处理,以此类推,直至发送给位于对象树模型上的最顶层对象,也就是说,无论任何事件,一定有接收者和接收者的事件处理程序来接收,事件处理程序有可能是父类的事件处理程序或者是父对象的事件处理程序或者是本类中的重写的事件处理程序

 

4.removePostedEvents

static void QCoreApplication::removePostedEvents(QObject *receiver, int eventType = 0)

删除事件队列中的所有事件,不要调用这个函数!!!

 

5.sendPostedEvents

static void QCoreApplication::sendPostedEvents(QObject *receiver = Q_NULLPTR, int event_type = 0)

立即分派事件排队中的所有事件,如果receiver为空,则event_type事件将被发送给所有对象。如果event_type为0,则将所有事件发送给接收者。这两个参数都由默认实参,也就是说,默认情况下,调用该函数后会将事件队列中的所有事件发送给QT程序中的所有对象

注意:窗口相关的事件不是由此函数分发,而是由函数processEvents()分发

 

6.processEvents

static void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents)
static void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime)

这个函数有两种重载形式,第一种形式是根据ProcessEventsFlags处理调用线程中所有还没处理的事件,第二种形式是根据ProcessEventsFlags在maxtime毫秒内处理调用线程中还没处理的事件

这个函数通常可以在长时间繁忙运行的QT程序中被调用,以保持QT程序对事件的响应速度

 

二、QT的t事件队列接口类QAbstractEventDispatcher

QAbstractEventDispatcher类提供了管理Qt事件队列的接口,事件分配器接收事件后,将它们发送到QCoreApplication或QApplication实例进行处理。QAbstractEventDispatcher是一个纯虚基类,具体的接口实现根据操作系统而在不同的子类中实现

其中的processEvents函数形式如下

virtual bool QAbstractEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) = 0;

该函数处理与标志匹配的未处理事件,直到没有更多事件可处理为止。 如果事件被处理,则返回true;否则,返回false。

如果在标志中设置了QEventLoop :: WaitForMoreEvents标志,则此函数的行为如下:

如果有未处理事件,则此函数在处理完事件后返回。

如果没有可用的事件,则此函数将会等待,直到有更多未处理事件为止,然后处理完新的事件后返回。

如果没有在标志中设置QEventLoop :: WaitForMoreEvents标志,并且没有未处理事件,则此函数将立即返回。

此函数不会连续处理事件; 在处理所有可获得的事件后,根据标志位看看是否需要等待新的事件或者直接返回

 

 

三、QT的事件循环类QEventLoop

QEventLoop类提供一种进入和退出事件循环的方法。

创建一个QEventLoop对象并对其调用exec()以启动事件循环。 从事件循环中,调用exit()将强制exec()返回,事件循环退出。

int QEventLoop::exec(ProcessEventsFlags flags = AllEvents)
void QEventLoop::exit(int returnCode = 0)

和QCoreApplication中的exec和exit的作用相同,因为QCoreApplication中的exec最终会创建QEventLoop对象并调用QEventLoop的exec

 

所以,QT的事件循环机制相关的主要类除了QObject外,还有三个,QCoreApplication负责事件的发送,QAbstractEventDispatcher负责事件队列的管理和事件队列的分发,QEventLoop负责创建事件循环

 

参考

https://doc.qt.io/Qt-5/qabstracteventdispatcher.html

https://doc.qt.io/Qt-5/eventsandfilters.html

https://doc.qt.io/Qt-5/qcoreapplication.html

https://doc.qt.io/Qt-5/qeventloop.html

 

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出


推荐阅读
  • Web动态服务器Python基本实现
    Web动态服务器Python基本实现 ... [详细]
  • 深入理解:AJAX学习指南
    本文详细探讨了AJAX的基本概念、工作原理及其在现代Web开发中的应用,旨在为初学者提供全面的学习资料。 ... [详细]
  • 本文探讨了如何通过优化 DOM 操作来提升 JavaScript 的性能,包括使用 `createElement` 函数、动画元素、理解重绘事件及处理鼠标滚动事件等关键主题。 ... [详细]
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • 本文介绍了如何通过C#语言调用动态链接库(DLL)中的函数来实现IC卡的基本操作,包括初始化设备、设置密码模式、获取设备状态等,并详细展示了将TextBox中的数据写入IC卡的具体实现方法。 ... [详细]
  • spring boot使用jetty无法启动 ... [详细]
  • 理解浏览器历史记录(2)hashchange、pushState
    阅读目录1.hashchange2.pushState本文也是一篇基础文章。继上文之后,本打算去研究pushState,偶然在一些信息中发现了锚点变 ... [详细]
  • Beetl是一款先进的Java模板引擎,以其丰富的功能、直观的语法、卓越的性能和易于维护的特点著称。它不仅适用于高响应需求的大型网站,也适合功能复杂的CMS管理系统,提供了一种全新的模板开发体验。 ... [详细]
  • Java 中的十进制样式 getZeroDigit()方法,示例 ... [详细]
  • 问题场景用Java进行web开发过程当中,当遇到很多很多个字段的实体时,最苦恼的莫过于编辑字段的查看和修改界面,发现2个页面存在很多重复信息,能不能写一遍?有没有轮子用都不如自己造。解决方式笔者根据自 ... [详细]
  • 数据类型--char一、char1.1char占用2个字节char取值范围:【0~65535】char采用unicode编码方式char类型的字面量用单引号括起来char可以存储一 ... [详细]
  • 本文介绍如何手动实现一个字符串连接函数,该函数不依赖于C语言的标准字符串处理函数,如strcpy或strcat。函数原型为void concatenate(char *dest, char *src),其主要作用是将源字符串src追加到目标字符串dest的末尾。 ... [详细]
  • importjava.io.*;importjava.util.*;publicclass五子棋游戏{staticintm1;staticintn1;staticfinalintS ... [详细]
  • 本文通过分析一个具体的案例,探讨了64位Linux系统对32位应用程序的兼容性问题。案例涉及OpenVPN客户端在64位系统上的异常行为,通过逐步排查和代码测试,最终定位到了与TUN/TAP设备相关的系统调用兼容性问题。 ... [详细]
author-avatar
墨镜元龙高卧
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有