QT 之 sendEvent & PostEvent

QT文档中这样解释:

sendEvent(QObject* receiver,QEvent* event)

使用notify()函数直接给receiver发送事件。

postEvent(QObject* receiver, QEvent* event)

向事件队列中添加receiver和event。

简单说,sendEvent使用的是同步处理事件,postEvent使用的异步处理事件


sendEvent代码分析

inline bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event)
{  if (event) event->spont = false; return self ? self->notifyInternal(receiver, event) : false; }

直接调用notifyInternal接口,注意中间设置自发消息标志位为false,同时还需要判断self是有有效(QCoreApplication是否启动)

bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
{
    // Make it possible for Qt Jambi and QSA to hook into events even
    // though QApplication is subclassed...
    bool result = false;
    void *cbdata[] = { receiver, event, &result };
    if (QInternal::activateCallbacks(QInternal::EventNotifyCallback, cbdata)) {
        return result;
    }

    // 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.
    QObjectPrivate *d = receiver->d_func();
    QThreadData *threadData = d->threadData;
    ++threadData->loopLevel;

    bool returnValue = notify(receiver, event);
    --threadData->loopLevel;
    return returnValue;
}
删除了一些不重要的代码,notifyInternal的主要作用是activateCallbacks,直接看notify

bool QCoreApplication::notify(QObject *receiver, QEvent *event)
{
    Q_D(QCoreApplication);
    // no events are delivered after ~QCoreApplication() has started
    if (QCoreApplicationPrivate::is_app_closing)
        return true;
    if (receiver == 0) {                        // serious error
        qWarning("QCoreApplication::notify: Unexpected null receiver");
        return true;
    }
    return receiver->isWidgetType() ? false : d->notify_helper(receiver, event);
}
这个接口在QT文档上有注释。注意其中当receiver为控件时,不进行处理。

bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{
    // send to all application event filters
    if (sendThroughApplicationEventFilters(receiver, event))
        return true;
    // send to all receiver event filters
    if (sendThroughObjectEventFilters(receiver, event))
        return true;
    // deliver the event
    return receiver->event(event);
}

在这里可以看到事件是如何处理的:

  • 先送入Application的事件过滤器,看看是否在事件过滤器中处理
  • 再查看receiver是否有此事件的过滤器
  • 最后,将事件送入receiver的event接口。

从整个过程来看,可以认为sendEvent直接调用了receiver的event接口。因此,可以认为处理方式为同步处理方式。


PostEvent分析

void QCoreApplication::postEvent(QObject *receiver, QEvent *event)
{
    postEvent(receiver, event, Qt::NormalEventPriority);
}
void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
{
    ...
    QThreadData * volatile * pdata = &receiver->d_func()->threadData;  //得到线程信息
    QThreadData *data = *pdata;
    if (!data) {
        // posting during destruction? just delete the event to prevent a leak
        delete event;
        return;
    }

    // lock the post event mutex
    data->postEventList.mutex.lock();

    // if object has moved to another thread, follow it
    while (data != *pdata) {                        <span style="font-family: Arial, Helvetica, sans-serif;">//在这里判断receiver线程信息是否发生变化。(有可能是另外一个线程调用用receiver->moveToThread)</span>
        data->postEventList.mutex.unlock();

        data = *pdata;
        if (!data) {
            // posting during destruction? just delete the event to prevent a leak
            delete event;
            return;
        }

        data->postEventList.mutex.lock();
    }
//这里postEventList还是被锁着的。
    // if this is one of the compressible events, do compression
    if (receiver->d_func()->postedEvents
        && self && self->compressEvent(event, receiver, &data->postEventList)) {
        data->postEventList.mutex.unlock();//这个事件有可能被压缩(实际上是发现队列中有这个事件还没有被处理,且这个事件是可以被压缩的,例如paintevent)
        return;
    }

    event->posted = true;
    ++receiver->d_func()->postedEvents;
    if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) {
        // remember the current running eventloop for DeferredDelete
        // events posted in the receiver's thread
        event->d = reinterpret_cast<QEventPrivate *>(quintptr(data->loopLevel)); //receiver即将被析构?
    }
//将事件添加到postEventList中,注意这里的优先级第一个最高,最后一个优先级最低
    if (data->postEventList.isEmpty() || data->postEventList.last().priority >= priority) {
        // optimization: we can simply append if the last event in
        // the queue has higher or equal priority
        data->postEventList.append(QPostEvent(receiver, event, priority));
    } else {
        // insert event in descending priority order, using upper
        // bound for a given priority (to ensure proper ordering
        // of events with the same priority)
        QPostEventList::iterator begin = data->postEventList.begin()
                                         + data->postEventList.insertionOffset,
                                   end = data->postEventList.end();
        QPostEventList::iterator at = qUpperBound(begin, end, priority);
        data->postEventList.insert(at, QPostEvent(receiver, event, priority));
    }
    data->canWait = false;
    data->postEventList.mutex.unlock();//在这里解除锁
//receiver所在的线程调用eventDispatcher处理postEventList
    if (data->eventDispatcher)
        data->eventDispatcher->wakeUp();
}
从上面可以看出,postEvent实际上是将事件添加到receiver所在线程中的一个队列中,至于这个队列所在的线程什么时候处理这个事件,postEvent是无法控制的








  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值