Qt GUI 通過滑鼠事件剖析整個事件處理流程(基於Qt4.5.2原始碼windows平臺)
阿新 • • 發佈:2019-01-10
/*以下分析的是Windows平臺 Qt GUI程式的事件產生,分發,處理全過程(基於Qt5.4.2原始碼整理) 以一個滑鼠按壓的事件為例子講述 ...表示省略掉一些程式碼(skip code) 事件起源: 基於事件如何被產生與分發,可以把事件分為以下三類。 Spontaneous 事件——自發事件 由視窗系統產生,它們被放到系統佇列中,通過事件迴圈逐個處理。(例如滑鼠事件、鍵盤事件) Posted 事件 由Qt或是應用程式產生,它們被Qt組成佇列,再通過事件迴圈處理。 Sent 事件 由Qt或是應用程式產生,但它們被直接傳送到目標物件。 Spontaneous 事件、Posted 事件都是post到事件佇列,迴圈處理 因為都是程式碼,所以推薦用Notepad++開啟本文件 */ //函式呼叫關係 main(int, char **) QApplication::exec() QCoreApplication::exec() QEventLoop::exec(ProcessEventsFlags ) QEventLoop::processEvents(ProcessEventsFlags ) QWindowsGuiEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) QWindowsGuiEventDispatcher::sendPostedEvents() QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags) QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e) QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e) QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event) QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) QApplication::notify(QObject *receiver, QEvent *e) QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) QWidgetWindow::event(QEvent *event) QWidgetWindow::handleMouseEvent(QMouseEvent *event) QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,QWidget *alienWidget, QWidget *nativeWidget, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,bool spontaneous) QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event) QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) QApplication::notify(QObject *receiver, QEvent *e) QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) QWidget::event(QEvent *event) //section 1 //Qt 程式入口,開啟事件迴圈 int main(int argc, char *argv[]) { QApplication app(argc, argv); Widget window; // Widget 繼承自QWidget window.show(); return app.exec(); // 進入QApplication事件迴圈=>見section 2 } //section 2 qapplication.cpp int QApplication::exec() { //呼叫QGuiApplication的exec=>見section 3 return QGuiApplication::exec(); } //section 3 qguiapplication.cpp int QGuiApplication::exec() { //如果可訪問,設定根物件 #ifndef QT_NO_ACCESSIBILITY QAccessible::setRootObject(qApp); #endif //呼叫QCoreApplication的exec=>見section 4 return QCoreApplication::exec(); } //section 4 qcoreapplication.cpp int QCoreApplication::exec() { ... QEventLoop eventLoop; self->d_func()->in_exec = true; self->d_func()->aboutToQuitEmitted = false; //委任eventLoop處理事件迴圈=>見section 5 int returnCode = eventLoop.exec(); ... return returnCode; } //section 5 qeventLoop.cpp int QEventLoop::exec(ProcessEventsFlags flags) { //獲取私有資料指標d Q_D(QEventLoop); ... //只要沒遇到退出就迴圈派發事件=>見section 6 while (!d->exit.loadAcquire()) { processEvents(flags | WaitForMoreEvents | EventLoopExec); } ... return d->returnCode.load(); } //section 6 qeventLoop.cpp bool QEventLoop::processEvents(ProcessEventsFlags flags) { Q_D(QEventLoop); //如果事件分發器等於空就返回false if (!d->threadData->eventDispatcher.load()) return false; //將事件派發給與平臺相關的QAbstractEventDispatcher子類 =>Section 7 return d->threadData->eventDispatcher.load()->processEvents(flags); } //section 7 qwindowsguieventdispatcher.cpp // 這段程式碼是完成與windows平臺相關的windows c++。以跨平臺著稱的Qt同時也提供了對Unix,Symiban等平臺的訊息派發支援 // QWindowsGuiEventDispatcher派生自QEventDispatcherWin32 QEventDispatcherWin32派生自QAbstractEventDispatcher. bool QWindowsGuiEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) { m_flags = flags; ... //呼叫基類的事件處理函式=>見section 8 const bool rc = QEventDispatcherWin32::processEvents(flags); ... return rc; } //section 8 qeventdispatcher_win.cpp bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) { Q_D(QEventDispatcherWin32); ... bool canWait; bool retVal = false; bool seenWM_QT_SENDPOSTEDEVENTS = false; bool needWM_QT_SENDPOSTEDEVENTS = false; do { 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; //事件迴圈標誌沒有排除使用者輸入標誌(ExcludeUserInputEvents) 、使用者輸入事件佇列非空 if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) { // process queued user input events haveMessage = true; //把使用者輸入事件佇列的第一個事件取出 msg = d->queuedUserInputEvents.takeFirst(); } //事件迴圈標誌沒有排除socket通知標誌(ExcludeSocketNotifiers) 、socket事件佇列非空 else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) { // process queued socket events haveMessage = true; //把socket事件佇列的第一個事件取出 msg = d->queuedSocketEvents.takeFirst(); } else { //偷窺一下,看有沒有訊息 haveMessage = PeekMessage(&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 || msg.message == WM_MOUSEHWHEEL || msg.message == WM_TOUCH #ifndef QT_NO_GESTURES || msg.message == WM_GESTURE || msg.message == WM_GESTURENOTIFY #endif || msg.message == WM_CLOSE)) { // queue user input events for later processing haveMessage = false; d->queuedUserInputEvents.append(msg); } if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers) && (msg.message == WM_QT_SOCKETNOTIFIER && 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(); } 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) { // WinCE doesn't support hooks at all, so we have to call this by hand :( if (!d->getMessageHook) { (void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg); } if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) { if (seenWM_QT_SENDPOSTEDEVENTS) { // when calling processEvents() "manually", we only want to send posted // events once needWM_QT_SENDPOSTEDEVENTS = true; continue; } seenWM_QT_SENDPOSTEDEVENTS = true; } else 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 (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) { //將事件打包成message呼叫Windows API派發出去 //分發一個訊息給視窗程式。訊息被分發到回撥函式,將訊息傳遞給windows系統,windows處理完畢,會呼叫回撥函式 => section 9 TranslateMessage(&msg); DispatchMessage(&msg); } } else if (waitRet - WAIT_OBJECT_0 < nCount) { 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 canWait = (!retVal && !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 | MWMO_INPUTAVAILABLE); emit awake(); if (waitRet - WAIT_OBJECT_0 < nCount) { d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0)); retVal = true; } } } while (canWait); if (!seenWM_QT_SENDPOSTEDEVENTS && (flags & QEventLoop::EventLoopExec) == 0) { // when called "manually", always send posted events sendPostedEvents(); } if (needWM_QT_SENDPOSTEDEVENTS) { PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); } return retVal; } //section 9 qeventdispatcher_win.cpp //呼叫回撥,將事件給視窗處理 LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) { if (message == WM_NCCREATE) return true; //重新組織訊息 MSG msg; msg.hwnd = hwnd; msg.message = message; msg.wParam = wp; msg.lParam = lp; QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); long result; if (!dispatcher) { if (message == WM_TIMER) KillTimer(hwnd, wp); return 0; } else if (dispatcher->filterNativeEvent(QByteArrayLiteral("windows_dispatcher_MSG"), &msg, &result)) { return result; } #ifdef GWLP_USERDATA QEventDispatcherWin32 *q = (QEventDispatcherWin32 *) GetWindowLongPtr(hwnd, GWLP_USERDATA); #else QEventDispatcherWin32 *q = (QEventDispatcherWin32 *) GetWindowLong(hwnd, GWL_USERDATA); #endif QEventDispatcherWin32Private *d = 0; if (q != 0) d = q->d_func(); if (message == WM_QT_SOCKETNOTIFIER) { // socket notifier message int type = -1; switch (WSAGETSELECTEVENT(lp)) { case FD_READ: case FD_ACCEPT: type = 0; break; case FD_WRITE: case FD_CONNECT: type = 1; break; case FD_OOB: type = 2; break; case FD_CLOSE: type = 3; break; } if (type >= 0) { Q_ASSERT(d != 0); QSNDict *sn_vec[4] = { &d->sn_read, &d->sn_write, &d->sn_except, &d->sn_read }; QSNDict *dict = sn_vec[type]; QSockNot *sn = dict ? dict->value(wp) : 0; if (sn) { if (type < 3) { QEvent event(QEvent::SockAct); QCoreApplication::sendEvent(sn->obj, &event); } else { QEvent event(QEvent::SockClose); QCoreApplication::sendEvent(sn->obj, &event); } } } return 0; } else if (message == WM_QT_SENDPOSTEDEVENTS // we also use a Windows timer to send posted events when the message queue is full || (message == WM_TIMER && d->sendPostedEventsWindowsTimerId != 0 && wp == (uint)d->sendPostedEventsWindowsTimerId)) { const int localSerialNumber = d->serialNumber.load(); if (localSerialNumber != d->lastSerialNumber) { d->lastSerialNumber = localSerialNumber; //派發post事件=> section 10 q->sendPostedEvents(); } return 0; } else if (message == WM_TIMER) { Q_ASSERT(d != 0); d->sendTimerEvent(wp); return 0; } //windows預設處理 return DefWindowProc(hwnd, message, wp, lp); } //從Section 1~Section9, Qt進入QApplication的event loop,經過層層委任, //最終QEventloop的processEvent將通過與平臺相關的QAbstractEventDispatcher的子類QEventDispatcherWin32獲得使用者的使用者輸入事件, //並將其打包成message後,通過標準Windows API ,把訊息傳遞給了Windows,Windows得到通知後回撥qt_internal_proc, 至此事件的分發與處理完成了一半的路程。 //section 10 qwindowsguieventdispatcher.cpp void QWindowsGuiEventDispatcher::sendPostedEvents() { QCoreApplication::sendPostedEvents(); //傳送windows系統事件m_flags == allEvents => section 11 QWindowSystemInterface::sendWindowSystemEvents(m_flags); } //section 11 qwindowsysteminterface.cpp bool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags) { int nevents = 0; while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) { QWindowSystemInterfacePrivate::WindowSystemEvent *event = (flags & QEventLoop::ExcludeUserInputEvents) ? QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent() : QWindowSystemInterfacePrivate::getWindowSystemEvent(); if (!event) break; nevents++; //處理windows系統事件 => section 12 QGuiApplicationPrivate::processWindowSystemEvent(event); delete event; } return (nevents > 0); } //section 12 qguiapplication.cpp void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e) { switch(e->type) { case QWindowSystemInterfacePrivate::FrameStrutMouse: case QWindowSystemInterfacePrivate::Mouse: //處理滑鼠事件=> section 13 QGuiApplicationPrivate::processMouseEvent(static_cast<QWindowSystemInterfacePrivate::MouseEvent *>(e)); break; ... } } //section 13 qguiapplication.cpp void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e) { QEvent::Type type; Qt::MouseButtons stateChange = e->buttons ^ buttons; ... //這裡實際物件指標是QWidgetWindow* QWindow *window = e->window.data(); modifier_buttons = e->modifiers; QPointF localPoint = e->localPos; QPointF globalPoint = e->globalPos; if (e->nullWindow) { window = QGuiApplication::topLevelAt(globalPoint.toPoint()); if (window) { QPointF delta = globalPoint - globalPoint.toPoint(); localPoint = window->mapFromGlobal(globalPoint.toPoint()) + delta; } } Qt::MouseButton button = Qt::NoButton; bool doubleClick = false; const bool frameStrut = e->type == QWindowSystemInterfacePrivate::FrameStrutMouse; if (QGuiApplicationPrivate::lastCursorPosition != globalPoint) { type = frameStrut ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove; QGuiApplicationPrivate::lastCursorPosition = globalPoint; if (qAbs(globalPoint.x() - mousePressX) > mouse_double_click_distance|| qAbs(globalPoint.y() - mousePressY) > mouse_double_click_distance) { mousePressButton = Qt::NoButton; } } else { // Check to see if a new button has been pressed/released. for (int check = Qt::LeftButton; check <= int(Qt::MaxMouseButton); check = check << 1) { if (check & stateChange) { button = Qt::MouseButton(check); break; } } if (button == Qt::NoButton) { // Ignore mouse events that don't change the current state. return; } mouse_buttons = buttons = e->buttons; if (button & e->buttons) { ulong doubleClickInterval = static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval()); doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton; type = frameStrut ? QEvent::NonClientAreaMouseButtonPress : QEvent::MouseButtonPress; mousePressTime = e->timestamp; mousePressButton = button; const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint(); mousePressX = point.x(); mousePressY = point.y(); } else { type = frameStrut ? QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease; } } if (!window) { return; } //這裡構造了Qt的滑鼠事件QMouseEvent QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, buttons, e->modifiers); ev.setTimestamp(e->timestamp); setMouseEventSource(&ev, e->source); #ifndef QT_NO_CURSOR if (!e->synthetic) { if (const QScreen *screen = window->screen()) if (QPlatformCursor *cursor = screen->handle()->cursor()) cursor->pointerEvent(ev); } #endif if (window->d_func()->blockedByModalWindow) { // a modal window is blocking this window, don't allow mouse events through return; } if (doubleClick && (ev.type() == QEvent::MouseButtonPress)) { // QtBUG-25831, used to suppress delivery in qwidgetwindow.cpp setMouseEventFlags(&ev, ev.flags() | Qt::MouseEventCreatedDoubleClick); } //傳送事件給相應視窗=> section 14 QGuiApplication::sendSpontaneousEvent(window, &ev); if (!e->synthetic && !ev.isAccepted() && !frameStrut && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) { if (!m_fakeTouchDevice) { m_fakeTouchDevice = new QTouchDevice; QWindowSystemInterface::registerTouchDevice(m_fakeTouchDevice); } QList<QWindowSystemInterface::TouchPoint> points; QWindowSystemInterface::TouchPoint point; point.id = 1; point.area = QRectF(globalPoint.x() - 2, globalPoint.y() - 2, 4, 4); // only translate left button related events to // avoid strange touch event sequences when several // buttons are pressed if (type == QEvent::MouseButtonPress && button == Qt::LeftButton) { point.state = Qt::TouchPointPressed; } else if (type == QEvent::MouseButtonRelease && button == Qt::LeftButton) { point.state = Qt::TouchPointReleased; } else if (type == QEvent::MouseMove && (buttons & Qt::LeftButton)) { point.state = Qt::TouchPointMoved; } else { return; } points << point; QEvent::Type type; QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::convertTouchPoints(points, &type); QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers); fake.synthetic = true; processTouchEvent(&fake); } if (doubleClick) { mousePressButton = Qt::NoButton; if (!e->window.isNull() || e->nullWindow) { // QTBUG-36364, check if window closed in response to press const QEvent::Type doubleClickType = frameStrut ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick; QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint, button, buttons, e->modifiers); dblClickEvent.setTimestamp(e->timestamp); setMouseEventSource(&dblClickEvent, e->source); //傳送事件給相應視窗=> section 14 QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent); } } } //section 14 qcoreapplication.cpp inline bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event) { //作為自發事件處理=> section 15 if (event) event->spont = true; return self ? self->notifyInternal(receiver, event) : false; } //section 15 qcoreapplication.cpp bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) { // Make it possible for Qt Script 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; QScopedLoopLevelCounter loopLevelCounter(threadData); //準備通知接受者(這裡是QWidgetWindow*)=> section 16 return notify(receiver, event); } //section 16 qapplication.cpp bool QApplication::notify(QObject *receiver, QEvent *e) { Q_D(QApplication); ... bool res = false; if (!receiver->isWidgetType()) { //通知接受者=> section 17 res = d->notify_helper(receiver, e); } ... return res; } //section 17 qapplication.cpp bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) { // send to all application event filters if (sendThroughApplicationEventFilters(receiver, e)) return true; if (receiver->isWidgetType()) { QWidget *widget = static_cast<QWidget *>(receiver); #if !defined(Q_OS_WINCE) || (defined(GWES_ICONCURS) && !defined(QT_NO_CURSOR)) // toggle HasMouse widget state on enter and leave if ((e->type() == QEvent::Enter || e->type() == QEvent::DragEnter) && (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == widget->window())) widget->setAttribute(Qt::WA_UnderMouse, true); else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave) widget->setAttribute(Qt::WA_UnderMouse, false); #endif if (QLayout *layout=widget->d_func()->layout) { layout->widgetEvent(e); } } // send to all receiver event filters if (sendThroughObjectEventFilters(receiver, e)) return true; // deliver the event =>section 18 bool consumed = receiver->event(e); QCoreApplicationPrivate::setEventSpontaneous(e, false); return consumed; } //section 18 qwidgetwindow.cpp bool QWidgetWindow::event(QEvent *event) { if (m_widget->testAttribute(Qt::WA_DontShowOnScreen)) { // \a event is uninteresting for QWidgetWindow, the event was probably // generated before WA_DontShowOnScreen was set return m_widget->event(event); } switch (event->type()) { ... case QEvent::MouseMove: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: //處理滑鼠事件 =>section 19 handleMouseEvent(static_cast<QMouseEvent *>(event)); return true; ... } return m_widget->event(event) || QWindow::event(event); } //section 19 qwidgetwindow.cpp void QWidgetWindow::handleMouseEvent(QMouseEvent *event) { ... QWidget *receiver = QApplicationPrivate::pickMouseReceiver(m_widget, event->windowPos().toPoint(), &mapped, event->type(), event->buttons(), qt_button_down, widget); ... if ((event->type() != QEvent::MouseButtonPress) || !(event->flags().testFlag(Qt::MouseEventCreatedDoubleClick))) { // The preceding statement excludes MouseButtonPress events which caused // creation of a MouseButtonDblClick event. QTBUG-25831 QMouseEvent translated(event->type(), mapped, event->windowPos(), event->screenPos(), event->button(), event->buttons(), event->modifiers()); QGuiApplicationPrivate::setMouseEventSource(&translated, QGuiApplicationPrivate::mouseEventSource(event)); translated.setTimestamp(event->timestamp()); //傳送滑鼠事件=>section 20 QApplicationPrivate::sendMouseEvent(receiver, &translated, widget, m_widget, &qt_button_down, qt_last_mouse_receiver); } ... } //section 20 qapplication.cpp bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, QWidget *nativeWidget, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver, bool spontaneous) { ... //傳送自發事件=> section 21 if (spontaneous) result = QApplication::sendSpontaneousEvent(receiver, event); ... } //section 21 qcoreapplication.cpp inline bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event) { //作為自發事件處理=> section 22 if (event) event->spont = true; return self ? self->notifyInternal(receiver, event) : false; } //section 22 qcoreapplication.cpp bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) { // Make it possible for Qt Script 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; QScopedLoopLevelCounter loopLevelCounter(threadData); //準備通知接受者(這裡就是我們的widget)=> section 23 return notify(receiver, event); } //section 23 qapplication.cpp bool QApplication::notify(QObject *receiver, QEvent *e) { Q_D(QApplication); ... bool res = false; if (!receiver->isWidgetType()) { //通知接受者=> section 24 res = d->notify_helper(receiver, e); } ... return res; } //section 24 qapplication.cpp bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) { // send to all application event filters if (sendThroughApplicationEventFilters(receiver, e)) return true; if (receiver->isWidgetType()) { QWidget *widget = static_cast<QWidget *>(receiver); #if !defined(Q_OS_WINCE) || (defined(GWES_ICONCURS) && !defined(QT_NO_CURSOR)) // toggle HasMouse widget state on enter and leave if ((e->type() == QEvent::Enter || e->type() == QEvent::DragEnter) && (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == widget->window())) widget->setAttribute(Qt::WA_UnderMouse, true); else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave) widget->setAttribute(Qt::WA_UnderMouse, false); #endif if (QLayout *layout=widget->d_func()->layout) { layout->widgetEvent(e); } } // send to all receiver event filters if (sendThroughObjectEventFilters(receiver, e)) return true; // deliver the event =>section 25 bool consumed = receiver->event(e); QCoreApplicationPrivate::setEventSpontaneous(e, false); return consumed; } //section 25 qwidget.cp bool QWidget::event(QEvent *event) { Q_D(QWidget); ... switch (event->type()) { case QEvent::MouseMove: mouseMoveEvent((QMouseEvent*)event); break; case QEvent::MouseButtonPress: mousePressEvent((QMouseEvent*)event); break; case QEvent::MouseButtonRelease: mouseReleaseEvent((QMouseEvent*)event); break; case QEvent::MouseButtonDblClick: mouseDoubleClickEvent((QMouseEvent*)event); break; ... default: return QObject::event(event); } return true; }