日志
QT5的post Event解析
2017-02-15 15:59
大家都知道,QT的事件机制,查了好多网上的帖子,分析的不够到位,今天给大家分享下,我的分析,请高手指正:
都知道post Event通过 QScopedPointer<QEvent> eventDeleter(event); //增加到事件队列 data->postEventList.addEvent(QPostEvent(receiver, event, priority)); eventDeleter.take(); event->posted = true; ++receiver->d_func()->postedEvents; data->canWait = false; locker.unlock(); //事件分发 QAbstractEventDispatcher* dispatcher = data->eventDispatcher.loadAcquire(); if (dispatcher) dispatcher->wakeUp(); 网上基本上讲到这里,也就结束了,post Event由于是异步事件,很多都说和操作系统有关,这是对的,但是,还没有往下深纠, 下面我往下进行深入的考察: QAbstractEventDispatcher,大家注意到这个类,这个类是一个抽象类,他是一个指针,指向的肯定是派生类。 他的派生类是什么呢?,他的派生类和平台相关,对于win下,他的派生类是QEventDispatcherWin32 这在QCore Application,就会创建,createEventDispatcher(),可以查看下这个里面的代码, void QEventDispatcherWin32::wakeUp() { Q_D(QEventDispatcherWin32); d->serialNumber.ref(); if (d->internalHwnd && d->wakeUps.testAndSetAcquire(0, 1)) { // post a WM_QT_SENDPOSTEDEVENTS to this thread if there isn't one already pending PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); } } 这里里面调用的是PostMessage,这个是win32的标准函数,这个就把消息添加到,win32的消息列队里面去了。 到这里大家也许就不知道怎么办了,下面是什么呢? 别忘了,回掉函数,最终要通过回掉函数,来处理消息的。 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) { #ifndef Q_OS_WINCE d->doWsaAsyncSelect(sn->fd, 0); d->active_fd[sn->fd].selected = false; d->postActivateSocketNotifiers(); #endif if (type < 3) { QEvent event(QEvent::SockAct); QCoreApplication::sendEvent(sn->obj, &event); } else { QEvent event(QEvent::SockClose); QCoreApplication::sendEvent(sn->obj, &event); } } } return 0; #ifndef Q_OS_WINCE } else if (message == WM_QT_ACTIVATENOTIFIERS) { Q_ASSERT(d != 0); // register all socket notifiers for (QSFDict::iterator it = d->active_fd.begin(), end = d->active_fd.end(); it != end; ++it) { QSockFd &sd = it.value(); if (!sd.selected) { d->doWsaAsyncSelect(it.key(), sd.event); sd.selected = true; } } d->activateNotifiersPosted = false; return 0; #endif // !Q_OS_WINCE } 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; q->sendPostedEvents(); } return 0; } else if (message == WM_TIMER) { Q_ASSERT(d != 0); d->sendTimerEvent(wp); return 0; } return DefWindowProc(hwnd, message, wp, lp); } 最终通过回掉函数处理消息,回掉函数中调用sendPostedEvents,或者是sendEvent,而sendPostedEvents,最终调用会通过 QCore Application::sendPostedEvents();调用而这个有用到了sendEvent。 而大家都知道sendEvent是同步的。 这就是postEvent的整个过程 |
下一篇: 无
上一篇: 无