QT5的post Event解析


大家都知道,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的整個過程

http://www.qtcn.org/bbs/apps.php?q=diary&uid=177993&a=detail&did=2356


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM