Qt中postEvent和sendEvent函数

Qt中postEvent和sendEvent函数

部分内容参考http://blog.csdn.net/lvmengzou/article/details/65450908

qt事件循环需要维护一个事件队列,在Qt的main函数中最后一般调用QApplication::exec()成员函数来保持程序对事件队列的处理,exec()的实质是不停调用processEvent()函数从队列中获取事件,并处理,然后删除,postEvent的作用就是发送一个事件到此队列中,由于删除队列中事件调用delete运算符,所以,postEvent()传递的事件一定要是动态分配的。

sendEvent()函数直接跳过事件循环队列,直接调用notify()函数发送事件到目标对象,并等待事件处理结果,所以其传递的事件直接在栈上分配即可,(postEvent()函数只负责添加事件到队列,不等待事件处理结果)。

sendEvent调用关系如下:

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

QCoreApplication::notifyInternal(QObject * receiver, QEvent * event)

QCoreApplication::notify(QObject * receiver, QEvent *event)

QCoreApplicationPrivate::notify_helper(QObject * receiver, QEvent * event)

最终调用receiver->event(event);

PostEvent()函数只是单纯添加事件到postEventList

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) {                        //在这里判断receiver线程信息是否发生变化。(有可能是另外一个线程调用用receiver->moveToThread)  
        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(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();  
}  

如果想查看Qt中QApplication::exec()函数是如何传递事件到目标对象,并根据notify返回值和事件isAccept()的返回值决定是否传递事件到目标对象的父对象,可以重载目标对象的事件处理函数,并在事件处理函数中加入断点,开始调试,然后在可执行程序界面上触发事件处理函数,程序就会在事件处理函数的断点处停止,然后逐级返回,查看整个调用情况,从processEvent()函数到最终我们重载的事件处理函数,至少有20层函数调用。(调试之前要安装Qt源码组件)


你可能感兴趣的:(Qt笔记,Qt笔记)