QT事件处理机制(发布事件)

原文链接:https://www.cnblogs.com/codegb/p/17274163.html

什么是事件循环?

在ChatGPT💬上搜索到的概念是:

在Qt中,事件循环是一种机制,用于处理各种异步事件。事件循环通过一个事件队列来管理和调度事件,当队列中有事件时,事件循环会从队列中依次取出事件并处理,直到队列为空或者事件循环被中断。

事件的产生可以是用户输入、系统信号、网络请求、定时器等,Qt提供了一系列的事件处理函数和信号槽机制,可以方便地将这些事件与具体的操作相绑定。

因此,Qt的事件循环机制是Qt应用程序实现异步响应和多线程编程的基础。

个人理解,Qt的事件循环是通过一个队列来循环处理事件的机制。当队列中有事件时,事件循环会处理事件;如果队列中没有事件,则事件循环会阻塞等待。

事件是如何产生的?

事件的产生可以分为两种:

  1. 程序外部产生:指系统产生的事件,例如鼠标按下(MouseButtonPress)、按键按下(KeyPress)等,这些事件会在事件发生后以msg格式加入到系统事件队列中。Qt通过捕捉系统事件,从系统事件队列中取出windows下msg格式的事件并将其封装成自己的QEvent类,再将事件发送出去。

  2. 程序内部产生:指在代码中手动创建一个事件,然后通过sendEvent/postEvent将事件发送到事件循环中。其中,sendEvent是阻塞型的发送方式,会等待事件处理完成后再继续执行;而postEvent是非阻塞型的发送方式,会将事件放入事件队列中,并立即返回。postEvent加入队列的事件被称为发布事件,加入的事件队列是发布事件队列。

事件是如何处理的?

让我们通过一个流程图简单了解事件从发出到处理的过程。
在接下来的解析中,我们将通过分析源代码,逐步验证流程图中的每个步骤。
在这里插入图片描述

下面我们将通过分析源码,来揭秘为什么sendEvent/postEvent是阻塞和非阻塞的、以及事件的处理流程。

sendEvent

首先,我们看sendEvent:

bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event)
{
   
	// sendEvent是阻塞调用
    Q_TRACE(QCoreApplication_sendEvent, receiver, event, event->type());

    if (event)
        event->spont = false;
    return notifyInternal2(receiver, event);
}

可以看到,sendEvent是调用了notifyInternal2这个函数

bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
{
   
	...
    // Qt enforces the rule that events can only be sent to objects in
    // the current thread, so receiver->d_func()->threadData is
    // equivalent to QThreadData::current(), just without the function
    // call overhead.
    // 事件只能在同一个线程被send
    QObjectPrivate *d = receiver->d_func();
    QThreadData *threadData = d->threadData;
    QScopedScopeLevelCounter scopeLevelCounter(threadData);
    if (!selfRequired)
        return doNotify(receiver, event);
    return self->notify(receiver, event);
}

进一步跟踪到其doNotify函数

static bool doNotify(QObject *receiver, QEvent *event)
{
   
    if (receiver == nullptr) {
                           // serious error
        qWarning("QCoreApplication::notify: Unexpected null receiver");
        return true;
    }

#ifndef QT_NO_DEBUG
	// 检查接受线程与当前是否同线程
    QCoreApplicationPrivate::checkReceiverThread(receiver);
#endif

	// QWidget类必须用QApplication
    return receiver->isWidgetType() ? false : QCoreApplicationPrivate::notify_helper(receiver, event);
}

然后就到了咱们这次分析的第一个重点——事件通知:QCoreApplicationPrivate::notify_helper

bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{
   
    // ...
}

通过分析这个函数,我们就可以大致知道事件处理的几个流程:

  1. 判断QCoreApplication有没有安装事件过滤器,有就把信号发送到QCoreApplication所安装事件过滤器里,由事件过滤器对事件进行处理。
// send to all application event filters (only does anything in the main thread)
if (QCoreApplication::self
    && receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread()
    && QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) {
   
    filtered = true;
    return filtered;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值