您的当前位置:首页正文

Qt GUI 通过鼠标事件剖析整个事件处理流程(基于Qt4.5.2源码windows平台)

2024-11-11 来源:个人技术集锦

/*以下分析的是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;
}


Top