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

 

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


推荐阅读
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
  • 本文详细介绍了 jQuery 的入门知识与实战应用,首先讲解了如何引入 jQuery 库及入口函数的使用方法,为初学者提供了清晰的操作指南。此外,还深入探讨了 jQuery 在实际项目中的多种应用场景,包括 DOM 操作、事件处理和 AJAX 请求等,帮助读者全面掌握 jQuery 的核心功能与技巧。 ... [详细]
  • iOS开发中MVC架构模式的深入解析(第一部分)
    在iOS开发中,MVC架构模式是常用的设计模式之一。本文将深入解析MVC架构的第一部分,重点介绍View组件。View组件继承自UIView,主要负责内容的展示(如UILabel等视图类)和用户输入的处理(如UIButton等控件类)。通过详细的代码示例和实际应用,帮助开发者更好地理解和掌握View在MVC架构中的作用和实现方式。 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • 如何在C#中配置组合框的背景颜色? ... [详细]
  • 在 Vue 应用开发中,页面状态管理和跨页面数据传递是常见需求。本文将详细介绍 Vue Router 提供的两种有效方式,帮助开发者高效地实现页面间的数据交互与状态同步,同时分享一些最佳实践和注意事项。 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • 本文总结了JavaScript的核心知识点和实用技巧,涵盖了变量声明、DOM操作、事件处理等重要方面。例如,通过`event.srcElement`获取触发事件的元素,并使用`alert`显示其HTML结构;利用`innerText`和`innerHTML`属性分别设置和获取文本内容及HTML内容。此外,还介绍了如何在表单中动态生成和操作``元素,以便更好地处理用户输入。这些技巧对于提升前端开发效率和代码质量具有重要意义。 ... [详细]
  • 如何在页面底部添加倾斜样式效果? ... [详细]
  • C#编程中按钮控件的使用与优化 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • 本文深入解析了Spring Cloud路由网关Zuul的核心功能及其典型应用场景。通过对方志朋老师教材的学习和实践,详细探讨了Zuul在微服务架构中的重要作用,包括请求路由、过滤器链管理以及服务动态扩展等关键特性。同时,结合实际案例,展示了Zuul在高并发和复杂业务场景下的应用优势,为读者提供了全面的技术参考。 ... [详细]
  • 在ASP.NET中,实现页面间数据传递有多种技术方案。其中一种常见方法是通过URL链接地址传递参数,例如在 `send.aspx` 页面中,可以通过点击按钮将数据附加到URL中,然后在目标页面 `receive.aspx` 中解析这些参数。此外,还可以利用Session、ViewState、Cookie等机制来实现跨页面的数据共享,每种方法都有其适用场景和优缺点。 ... [详细]
  • 开发笔记:深入解析Android自定义控件——Button的72种变形技巧
    开发笔记:深入解析Android自定义控件——Button的72种变形技巧 ... [详细]
  • Eclipse JFace Text框架中IDocument接口的getNumberOfLines方法详解与编程实例 ... [详细]
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社区 版权所有