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
- Qt GUI 通过鼠标事件剖析整个事件处理流程(基于Qt4.5.2源码windows平台)
- Qt事件处理机制整个流程--以鼠标在一个窗口中点击为例
- Qt事件处理机制整个流程--以鼠标在一个窗口中点击为例
- Activity启动流程,界面绘制到事件处理的整个流程(基于Android6.0源码)(1)
- Activity启动流程,界面绘制到事件处理的整个流程(基于Android6.0源码)(2)
- Activity启动流程,界面绘制到事件处理的整个流程(基于Android6.0源码)(3)
- 初步剖析QT事件处理过程(Windows)(上)
- C++ GUI Qt4编程-事件处理
- 剖析Qt 事件的产生、分发、接受、处理流程
- Qt 处理鼠标点击事件
- [Java GUI] 鼠标移动事件处理示例
- QT事件处理,鼠标事件,按键键盘事件,定时器,进度条。
- QT平台上模拟鼠标事件案例
- Opencv 鼠标事件GUI
- java GUI 鼠标事件
- Qt源码之事件处理
- Android源码事件传递流程剖析
- Qt 键盘、鼠标事件的处理
- FindBugs 错误信息汇总
- eclipse svn滤过不需要提交的文件和文件夹
- 拷贝构造函数
- LeetCode(46) Permutations
- Matlab分析证券相关系数
- Qt GUI 通过鼠标事件剖析整个事件处理流程(基于Qt4.5.2源码windows平台)
- android技术 面试题 笔试题精华重点
- iOS动画集合
- Android四大基本组件介绍与生命周期
- ubuntu 12.04下编译安装nginx-1.9.3
- 关于XShell上登录跳板机问题及第七天实习记录
- Linux内核Socket参数调优
- Android-横屏应用在竖屏情况下解锁引起销毁
- [Object-C] AutoLaout入门