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