• 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

  • 相关阅读:
    Python 命令模式和交互模式
    Python自带IDE设置字体
    Python2.7和3.7区别
    Kubernetes1.91(K8s)安装部署过程(八)-- kubernetes-dashboard安装
    Kubernetes1.91(K8s)安装部署过程(七)--coredns安装
    nginx 设置自签名证书以及设置网址http强制转https访问
    Kubernetes1.91(K8s)安装部署过程(六)--node节点部署
    VMware安装VMware tool是 遇到The path "" is not a valid path to the 3.10.0-693.el7.x86_64 kernel headers.
    第三方git pull免密码更新
    Kubernetes1.91(K8s)安装部署过程(五)--安装flannel网络插件
  • 原文地址:https://www.cnblogs.com/findumars/p/6413821.html
Copyright © 2020-2023  润新知