浅谈QApplication的事件循环机制

概述

本文仅浅浅的介绍些许QApplication相关的事件循环。

详情

Qt是以事件为驱动的。接下来浅谈一下。

线程相关性

在这里插入图片描述

当我们创建一个QObject时,它会与创建自己所在的线程绑定。它参与的消息循环,其实是它所在线程的消息循环,如上图所示。假如某个线程没有默认的QThread::exec(),那么该线程上的QObject则无法接收到事件。另外,如果两个不同线程的QObject需要相互通信,那么只能通过QueuedConnection的方式,异步通知对方线程,在下一轮消息循环处理QObject的消息。

QObject的线程相关性默认会和它的parent保持一致。如果一个QObject没有parent,那么可以通过moveToThread,将它的线程相关性切换到指定线程。

Qt事件循环(以Windows为例)

Qt事件循环是基于Windows消息处理。Qt将系统消息(软件中断,像窗体的鼠标、键盘、输入法、绘制,各种消息)转换成Qt事件,并且将事件封装成类,所有的事件类都是由QEvent派生的,事件的产生和处理就是Qt程序的主轴,且伴随整个程序的运行周期。
当程序启动之后,进入main函数,main函数中会有一个QApplication(QCoreApplication)对象,该对象会调用exec,此时当前程序的事件循环被启动,之后QApplication(QCoreApplication)不断的从系统获取消息,这些消息转换为事件,存入事件队列,事件循环没有退出之前,会不断从队列中取事件,然后进行事件的分发,到指定的类对象的具体事件进行事件处理。
在Qt中,消息循环在QEventLoop类中实现。通过QEventLoop::exec()可以进入一个消息循环的阻塞状态中,也就是不断地PeekMessage-DispatchMessage进行消息的获取和分发。

以示例的方式展示运行流程

本文采用一个常用的例子为示例。

示例

本文开始的一个示例,是以创建QApplication应用程序为例,基于QDialog的应用程序。这里仅展示main.cpp中的代码,用以说明QApplication的事件循环机制。
main.cpp

#include "dialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    
    
    QApplication a(argc, argv);
    Dialog w;
    w.show();

    return a.exec();
}

其中a.exec()为启动事件循环。安装Qt源码,并且下载对应编译器的调试文件之后,可以在a.exec()这行打断点调试,F11进入到源码中可以看到:
在这里插入图片描述
QApplication调用了QGuiApplication的事件循环exec(),而在QGuiApplication中:
在这里插入图片描述
在这里插入图片描述
又调用QCoreApplication的事件循环exec(),其函数的实现如下:
在这里插入图片描述
先是判断当前线程是不是主线程,因为mian函数中的exec()事件循环是在主线程中启动的,且当前主线程的事件循环中还没有任何需要处理的事件,所以为空,接下来创建了QEventloop对象,并调用了exec(),启动了QEventloop的事件循环。此时要是没有相应的事件发生,如鼠标,键盘之类的事件,断点便在此exec处停滞。直到有事件发生。
QEventLoop的事件循环函数源码如下:
在这里插入图片描述
这里默认是处理所有的事件。真正的处理工作是在ProcessEvents(flags|…),中进行的,当没有事件的时候,会一直阻塞等待事件到来。其函数processEvent内部实现如下:
在这里插入图片描述
若没有事件分发,则while循环为一个空循环,若有事件调度,则调用processEvent处理事件。
在这里插入图片描述
在这里插入图片描述
QEventDispatcherWin32此类负责消息的获取和分发。
在这里插入图片描述
在这里插入图片描述
其本质上就是等待消息到来,然后将系统消息转换为Qt事件,进行事件分发,到具体的窗口类中进行事件处理。

事件循环在工作中的使用

参考文章

https://zhuanlan.zhihu.com/p/113695485

猜你喜欢

转载自blog.csdn.net/blqzj214817/article/details/128178329
今日推荐