Qt中事件分發原始碼剖析
阿新 • • 發佈:2018-12-30
Qt中事件傳遞順序:
在一個應該程式中,會進入一個事件迴圈,接受系統產生的事件,並且進行分發,這些都是在exec中進行的。下面舉例說明:
1)首先看看下面一段示例程式碼:
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- MouseEvent w;
- w.show();
- returna.exec();
- }
2)a.exec進入事件迴圈,呼叫的是QApplication::exec();
- int QApplication::exec()
- {
-
return
- }
3)QApplication::exec()呼叫的是QGuiApplication::exec();
- int QGuiApplication::exec()
- {
- #ifndef QT_NO_ACCESSIBILITY
- QAccessible::setRootObject(qApp);
- #endif
- returnQCoreApplication::exec();
- }
4)QGuiApplication::exec()呼叫的是QCoreApplication::exec();
-
int QCoreApplication::exec()
- {
- if (!QCoreApplicationPrivate::checkInstance("exec"))
- return -1;
- QThreadData *threadData = self->d_func()->threadData;
- if (threadData != QThreadData::current()) {
-
qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
- return -1;
- }
- if (!threadData->eventLoops.isEmpty()) {
- qWarning("QCoreApplication::exec: The event loop is already running");
- return -1;
- }
- threadData->quitNow = false;
- QEventLoop eventLoop;
- self->d_func()->in_exec = true;
- self->d_func()->aboutToQuitEmitted = false;
- int returnCode = eventLoop.exec();
- threadData->quitNow = false;
- if (self) {
- self->d_func()->in_exec = false;
- if (!self->d_func()->aboutToQuitEmitted)
- emit self->aboutToQuit(QPrivateSignal());
- self->d_func()->aboutToQuitEmitted = true;
- sendPostedEvents(0, QEvent::DeferredDelete);
- }
- return returnCode;
- }
5)QCoreApplication::exec()呼叫eventLoop.exec()進行事件迴圈;
- int QEventLoop::exec(ProcessEventsFlags flags)
- {
- Q_D(QEventLoop);
- //we need to protect from race condition with QThread::exit
- QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex);
- if (d->threadData->quitNow)
- return -1;
- if (d->inExec) {
- qWarning("QEventLoop::exec: instance %p has already called exec()", this);
- return -1;
- }
- struct LoopReference {
- QEventLoopPrivate *d;
- QMutexLocker &locker;
- bool exceptionCaught;
- LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)
- {
- d->inExec = true;
- d->exit = false;
- ++d->threadData->loopLevel;
- d->threadData->eventLoops.push(d->q_func());
- locker.unlock();
- }
- ~LoopReference()
- {
- if (exceptionCaught) {
- qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
- "exceptions from an event handler is not supported in Qt. You must\n"
- "reimplement QApplication::notify() and catch all exceptions there.\n");
- }
- locker.relock();
- QEventLoop *eventLoop = d->threadData->eventLoops.pop();
- Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
- Q_UNUSED(eventLoop); // --release warning
- d->inExec = false;
- --d->threadData->loopLevel;
- }
- };
- LoopReference ref(d, locker);
- // remove posted quit events when entering a new event loop
- QCoreApplication *app = QCoreApplication::instance();
- if (app && app->thread() == thread())
- QCoreApplication::removePostedEvents(app, QEvent::Quit);
- while (!d->exit)
- processEvents(flags | WaitForMoreEvents | EventLoopExec);
- ref.exceptionCaught = false;
- return d->returnCode;
- }
6)eventLoop.exec()呼叫QCoreApplication的processEvents進行事件分發;
7)呼叫notify進行分發
QCoreApplication::sendEvent、QCoreApplication::postEvent和QCoreApplication::sendPostedEvents都呼叫notify進行事件分發;
- bool QCoreApplication::notify(QObject *receiver, QEvent *event)
- {
- Q_D(QCoreApplication);
- // no events are delivered after ~QCoreApplication() has started
- if (QCoreApplicationPrivate::is_app_closing)
- returntrue;
- if (receiver == 0) { // serious error
- qWarning("QCoreApplication::notify: Unexpected null receiver");
- returntrue;
- }
- #ifndef QT_NO_DEBUG
- d->checkReceiverThread(receiver);
- #endif
- return receiver->isWidgetType() ? false :d->notify_helper(receiver, event);
- }
8)notify呼叫notify_helper進行事件分發;
- bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
- {
- // send to all application event filters
- if (sendThroughApplicationEventFilters(receiver, event))
- returntrue;
- // send to all receiver event filters
- if (sendThroughObjectEventFilters(receiver, event))
- returntrue;
- // deliver the event
- returnreceiver->event(event);
- }
9)從上面第8步的程式碼可以看出事件傳遞
傳遞的順序是:首先傳遞給全域性的事件過濾器,再傳遞給目標物件的事件過濾器,最終傳遞給目標物件。