1. 程式人生 > >Qt中事件分發原始碼剖析

Qt中事件分發原始碼剖析

Qt中事件傳遞順序:

在一個應該程式中,會進入一個事件迴圈,接受系統產生的事件,並且進行分發,這些都是在exec中進行的。
下面舉例說明:

1)首先看看下面一段示例程式碼:

  1. int main(int argc, char *argv[])  
  2. {  
  3.     QApplication a(argc, argv);  
  4.     MouseEvent w;  
  5.     w.show();  
  6.     returna.exec();
  7. }  

2)a.exec進入事件迴圈,呼叫的是QApplication::exec();

  1. int QApplication::exec()  
  2. {  
  3.     return
    QGuiApplication::exec();
  4. }  

3)QApplication::exec()呼叫的是QGuiApplication::exec();

  1. int QGuiApplication::exec()  
  2. {  
  3. #ifndef QT_NO_ACCESSIBILITY
  4.     QAccessible::setRootObject(qApp);  
  5. #endif
  6.     returnQCoreApplication::exec();
  7. }  

4)QGuiApplication::exec()呼叫的是QCoreApplication::exec();

  1. int QCoreApplication::exec()  
  2. {  
  3.     if (!QCoreApplicationPrivate::checkInstance("exec"))  
  4.         return -1;  
  5.     QThreadData *threadData = self->d_func()->threadData;  
  6.     if (threadData != QThreadData::current()) {  
  7.         qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());  
  8.         return -1;  
  9.     }  
  10.     if (!threadData->eventLoops.isEmpty()) {  
  11.         qWarning("QCoreApplication::exec: The event loop is already running");  
  12.         return -1;  
  13.     }  
  14.     threadData->quitNow = false;  
  15.     QEventLoop eventLoop;  
  16.     self->d_func()->in_exec = true;  
  17.     self->d_func()->aboutToQuitEmitted = false;  
  18.     int returnCode = eventLoop.exec();
  19.     threadData->quitNow = false;  
  20.     if (self) {  
  21.         self->d_func()->in_exec = false;  
  22.         if (!self->d_func()->aboutToQuitEmitted)  
  23.             emit self->aboutToQuit(QPrivateSignal());  
  24.         self->d_func()->aboutToQuitEmitted = true;  
  25.         sendPostedEvents(0, QEvent::DeferredDelete);  
  26.     }  
  27.     return returnCode;  
  28. }  

5)QCoreApplication::exec()呼叫eventLoop.exec()進行事件迴圈;

  1. int QEventLoop::exec(ProcessEventsFlags flags)  
  2. {  
  3.     Q_D(QEventLoop);  
  4.     //we need to protect from race condition with QThread::exit
  5.     QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex);  
  6.     if (d->threadData->quitNow)  
  7.         return -1;  
  8.     if (d->inExec) {  
  9.         qWarning("QEventLoop::exec: instance %p has already called exec()"this);  
  10.         return -1;  
  11.     }  
  12.     struct LoopReference {  
  13.         QEventLoopPrivate *d;  
  14.         QMutexLocker &locker;  
  15.         bool exceptionCaught;  
  16.         LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)  
  17.         {  
  18.             d->inExec = true;  
  19.             d->exit = false;  
  20.             ++d->threadData->loopLevel;  
  21.             d->threadData->eventLoops.push(d->q_func());  
  22.             locker.unlock();  
  23.         }  
  24.         ~LoopReference()  
  25.         {  
  26.             if (exceptionCaught) {  
  27.                 qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
  28.                          "exceptions from an event handler is not supported in Qt. You must\n"
  29.                          "reimplement QApplication::notify() and catch all exceptions there.\n");  
  30.             }  
  31.             locker.relock();  
  32.             QEventLoop *eventLoop = d->threadData->eventLoops.pop();  
  33.             Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()""internal error");  
  34.             Q_UNUSED(eventLoop); // --release warning
  35.             d->inExec = false;  
  36.             --d->threadData->loopLevel;  
  37.         }  
  38.     };  
  39.     LoopReference ref(d, locker);  
  40.     // remove posted quit events when entering a new event loop
  41.     QCoreApplication *app = QCoreApplication::instance();  
  42.     if (app && app->thread() == thread())  
  43.         QCoreApplication::removePostedEvents(app, QEvent::Quit);  
  44.     while (!d->exit)  
  45.         processEvents(flags | WaitForMoreEvents | EventLoopExec);  
  46.     ref.exceptionCaught = false;  
  47.     return d->returnCode;  
  48. }  

6)eventLoop.exec()呼叫QCoreApplication的processEvents進行事件分發;

7)呼叫notify進行分發

QCoreApplication::sendEvent、QCoreApplication::postEvent和QCoreApplication::sendPostedEvents都呼叫notify進行事件分發;

  1. bool QCoreApplication::notify(QObject *receiver, QEvent *event)  
  2. {  
  3.     Q_D(QCoreApplication);  
  4.     // no events are delivered after ~QCoreApplication() has started
  5.     if (QCoreApplicationPrivate::is_app_closing)  
  6.         returntrue;  
  7.     if (receiver == 0) {                        // serious error
  8.         qWarning("QCoreApplication::notify: Unexpected null receiver");  
  9.         returntrue;  
  10.     }  
  11. #ifndef QT_NO_DEBUG
  12.     d->checkReceiverThread(receiver);  
  13. #endif
  14.     return receiver->isWidgetType() ? false :d->notify_helper(receiver, event);  
  15. }  

8)notify呼叫notify_helper進行事件分發;

  1. bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)  
  2. {  
  3.     // send to all application event filters
  4.     if (sendThroughApplicationEventFilters(receiver, event))  
  5.         returntrue;  
  6.     // send to all receiver event filters
  7.     if (sendThroughObjectEventFilters(receiver, event))  
  8.         returntrue;  
  9.     // deliver the event
  10.     returnreceiver->event(event);  
  11. }  

9)從上面第8步的程式碼可以看出事件傳遞

傳遞的順序是:首先傳遞給全域性的事件過濾器,再傳遞給目標物件的事件過濾器,最終傳遞給目標物件。