热门标签 | 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

 

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


推荐阅读
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 本文介绍了如何在C#中启动一个应用程序,并通过枚举窗口来获取其主窗口句柄。当使用Process类启动程序时,我们通常只能获得进程的句柄,而主窗口句柄可能为0。因此,我们需要使用API函数和回调机制来准确获取主窗口句柄。 ... [详细]
  • 本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ... [详细]
  • andr ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • ImmutableX Poised to Pioneer Web3 Gaming Revolution
    ImmutableX is set to spearhead the evolution of Web3 gaming, with its innovative technologies and strategic partnerships driving significant advancements in the industry. ... [详细]
  • 本文介绍如何使用 NSTimer 实现倒计时功能,详细讲解了初始化方法、参数配置以及具体实现步骤。通过示例代码展示如何创建和管理定时器,确保在指定时间间隔内执行特定任务。 ... [详细]
  • 本文介绍了如何通过 Maven 依赖引入 SQLiteJDBC 和 HikariCP 包,从而在 Java 应用中高效地连接和操作 SQLite 数据库。文章提供了详细的代码示例,并解释了每个步骤的实现细节。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • Splay Tree 区间操作优化
    本文详细介绍了使用Splay Tree进行区间操作的实现方法,包括插入、删除、修改、翻转和求和等操作。通过这些操作,可以高效地处理动态序列问题,并且代码实现具有一定的挑战性,有助于编程能力的提升。 ... [详细]
  • 本文详细介绍了Java中org.w3c.dom.Text类的splitText()方法,通过多个代码示例展示了其实际应用。该方法用于将文本节点在指定位置拆分为两个节点,并保持在文档树中。 ... [详细]
  • 本文详细介绍了 Apache Jena 库中的 Txn.executeWrite 方法,通过多个实际代码示例展示了其在不同场景下的应用,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 本文详细介绍了Java中的访问器(getter)和修改器(setter),探讨了它们在保护数据完整性、增强代码可维护性方面的重要作用。通过具体示例,展示了如何正确使用这些方法来控制类属性的访问和更新。 ... [详细]
  • 本文详细探讨了VxWorks操作系统中双向链表和环形缓冲区的实现原理及使用方法,通过具体示例代码加深理解。 ... [详细]
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社区 版权所有