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

来源:互联网 发布:重生之玩物人生知轩 编辑:程序博客网 时间:2024/06/05 03:41

/*以下分析的是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.cppint QApplication::exec(){//调用QGuiApplication的exec=>见section 3    return QGuiApplication::exec();}//section 3 qguiapplication.cppint QGuiApplication::exec(){//如果可访问,设置根对象#ifndef QT_NO_ACCESSIBILITY    QAccessible::setRootObject(qApp);#endif//调用QCoreApplication的exec=>见section 4    return QCoreApplication::exec();}//section 4 qcoreapplication.cppint 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.cppint 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.cppbool 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.cppvoid QWindowsGuiEventDispatcher::sendPostedEvents(){    QCoreApplication::sendPostedEvents();//发送windows系统事件m_flags == allEvents => section 11    QWindowSystemInterface::sendWindowSystemEvents(m_flags);}//section 11 qwindowsysteminterface.cppbool 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.cppvoid 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.cppvoid 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.cppinline bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event){ //作为自发事件处理=> section 15if (event) event->spont = true; return self ? self->notifyInternal(receiver, event) : false; }//section 15 qcoreapplication.cppbool 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.cppbool 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.cppbool 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.cppbool 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.cppvoid 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.cppbool 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.cppinline bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event){ //作为自发事件处理=> section 22if (event) event->spont = true; return self ? self->notifyInternal(receiver, event) : false; }//section 22 qcoreapplication.cppbool 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.cppbool 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.cppbool 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.cpbool 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;}


0 0