QT 源碼之 Qt 事件機制原理是本文要介紹的內容,在用Qt寫Gui程序的時候,在main函數里面最后依據都是app.exec();很多書上對這句的解釋是,使 Qt 程序進入消息循環。下面我們就到exec()函數內部,來看一下他的實現原理。
Let's go!
首先來到QTDIR\src\corelib\kernel\qcoreapplication.cpp
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; } //判斷eventLoop是否已經創建 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; //創建eventLoop int returnCode = eventLoop.exec(); threadData->quitNow = false; if (self) { self->d_func()->in_exec = false; //退出程序 emit self->aboutToQuit(); sendPostedEvents(0, QEvent::DeferredDelete); } return returnCode; } 再來到qeventloop.cpp中。 int QEventLoop::exec(ProcessEventsFlags flags) { Q_D(QEventLoop); if (d->threadData->quitNow) return -1; //已經調用過exec了。 if (d->inExec) { qWarning("QEventLoop::exec: instance %p has already called exec()", this); return -1; } d->inExec = true; d->exit = false; ++d->threadData->loopLevel; //將事件類對象壓入線程結構體中 d->threadData->eventLoops.push(this); // remove posted quit events when entering a new event loop // 這句不用翻譯了把! if (qApp->thread() == thread()) QCoreApplication::removePostedEvents(qApp, QEvent::Quit); #if defined(QT_NO_EXCEPTIONS) while (!d->exit) //這里才是關鍵,我們還要繼續跟蹤進去。 processEvents(flags | WaitForMoreEvents); #else try { while (!d->exit) processEvents(flags | WaitForMoreEvents); } catch (...) { //如果使用了EXCEPTION,則繼續對下一條時間進行處理。 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"); throw; } #endif //退出eventloop前,將時間對象從線程結構中取出。 QEventLoop *eventLoop = d->threadData->eventLoops.pop(); Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error"); Q_UNUSED(eventLoop); // --release warning d->inExec = false; --d->threadData->loopLevel; //退出事件循環。 return d->returnCode; } 來到了processEvents函數: bool QEventLoop::processEvents(ProcessEventsFlags flags) { Q_D(QEventLoop); //判斷事件分派器是否為空。 if (!d->threadData->eventDispatcher) return false; if (flags & DeferredDeletion) QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); //調用不同平台下的事件分派器來處理事件。 return d->threadData->eventDispatcher->processEvents(flags); } processEvents是在QAbstractEventDispatcher類中定義的純虛方法。在QEventDispatcherWin32類有processEvents的實現。 bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) { Q_D(QEventDispatcherWin32); //內部數據創建。registerClass注冊窗口類,createwindow創建窗體。 //注冊socket notifiers,啟動所有的normal timers if (!d->internalHwnd) createInternalHwnd(); d->interrupt = false; emit awake(); bool canWait; bool retVal = false; do { QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); DWORD waitRet = 0; HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1]; QVarLengthArray<MSG> processedTimers; while (!d->interrupt) { DWORD nCount = d->winEventNotifierList.count(); Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1); MSG msg; bool haveMessage; if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) { // process queued user input events處理用戶輸入事件,放入隊列中。 haveMessage = true; msg = d->queuedUserInputEvents.takeFirst(); } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) { // process queued socket events 處理socket事件,放入隊列中。 haveMessage = true; msg = d->queuedSocketEvents.takeFirst(); } else { //從消息隊列中取消息,同PeekMessage haveMessage = winPeekMessage(&msg, 0, 0, 0, PM_REMOVE); if (haveMessage && (flags & QEventLoop::ExcludeUserInputEvents) && ((msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) || (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) || msg.message == WM_MOUSEWHEEL)) { // queue user input events for later processing haveMessage = false; d->queuedUserInputEvents.append(msg); } if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers) && (msg.message == WM_USER && msg.hwnd == d->internalHwnd)) { // queue socket events for later processing haveMessage = false; d->queuedSocketEvents.append(msg); } } if (!haveMessage) { // no message - check for signalled objects for (int i=0; i<(int)nCount; i++) pHandles[i] = d->winEventNotifierList.at(i)->handle(); //注冊signal--slot。 waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE); if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) { // a new message has arrived, process it continue; } } //事件隊列中有事件需要處理。 if (haveMessage) { //處理timer事件 if (msg.message == WM_TIMER) { // avoid live-lock by keeping track of the timers we've already sent bool found = false; for (int i = 0; !found && i < processedTimers.count(); ++i) { const MSG processed = processedTimers.constData()[i]; found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam); } if (found) continue; processedTimers.append(msg); } else if (msg.message == WM_QUIT) { if (QCoreApplication::instance()) QCoreApplication::instance()->quit(); return false; } //消息分發處理。 if (!filterEvent(&msg)) { TranslateMessage(&msg); QT_WA({ DispatchMessage(&msg); } , { DispatchMessageA(&msg); }); } } else if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) { //處理signal--slot d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0)); } else { // nothing todo so break break; } retVal = true; } // still nothing - wait for message or signalled objects QThreadData *ddata = d->threadData; canWait = (!retVal && data->canWait && !d->interrupt && (flags & QEventLoop::WaitForMoreEvents)); if (canWait) { DWORD nCount = d->winEventNotifierList.count(); Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1); for (int i=0; i<(int)nCount; i++) pHandles[i] = d->winEventNotifierList.at(i)->handle(); emit aboutToBlock(); waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE); emit awake(); if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) { d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0)); retVal = true; } } } while (canWait); return retVal; }
小結:關於詳解 QT 源碼之 Qt 事件機制原理的內容介紹完了,基本屬於代碼實現的內容,最后希望本文對你有幫助!