Qt在windows平台下的消息循环——Qt进阶第二天

一、背景

万事开头难,前几天花了两天时间终于搭建好了Qt的源码调试环境,认识一个系统,最先要搞清楚的就是消息循环和事件分发机制,这是之后继续深入学习qt的前提,话不多说,直接开撸。

二、代码走读

1.QApplication

相信任何人学习Qt的第一行代码就是QApplication,最后一行代码也是它。我坚信,这个类和消息循环关系匪浅。别急,我们先看看它的构造函数:
QApplication构造函数
Q_D这个宏是取private类(内部实现),赋值给变量d。
进入init函数:
在这里插入图片描述可以看到初始化相下抛了,后面会一直抛到祖先类:QCoreApplicationPrivate的init函数。
然后在里面有一个很重要的动作,创建平台相关的消息分发器QAbstractEventDispatcher(接口类):
在这里插入图片描述
这里的派生类:
在这里插入图片描述
它会设置个名字,具体看看createInternalHwnd
在这里插入图片描述
在这里插入图片描述
创建完内部窗体后,qt还安装了一个消息hook:
在这里插入图片描述
您将安装一个挂钩过程来监视系统中的某些类型的事件。这些事件与特定线程或与调用线程在同一桌面上的所有线程相关联。

我们继续。

三、Qt是如何处理每个QWidget窗口消息的?

QString QWindowsContext::registerWindowClass(const QWindow *w)
{
    Q_ASSERT(w);
    const Qt::WindowFlags flags = w->flags();
    const Qt::WindowFlags type = flags & Qt::WindowType_Mask;
    // Determine style and icon.
    uint style = CS_DBLCLKS;
    bool icon = true;
    // The following will not set CS_OWNDC for any widget window, even if it contains a
    // QOpenGLWidget or QQuickWidget later on. That cannot be detected at this stage.
    if (w->surfaceType() == QSurface::OpenGLSurface || (flags & Qt::MSWindowsOwnDC))
        style |= CS_OWNDC;
    if (!(flags & Qt::NoDropShadowWindowHint) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)
        && (type == Qt::Popup || w->property("_q_windowsDropShadow").toBool())) {
        style |= CS_DROPSHADOW;
    }
    switch (type) {
    case Qt::Tool:
    case Qt::ToolTip:
    case Qt::Popup:
        style |= CS_SAVEBITS; // Save/restore background
        icon = false;
        break;
    case Qt::Dialog:
        if (!(flags & Qt::WindowSystemMenuHint))
            icon = false; // QTBUG-2027, dialogs without system menu.
        break;
    }
    // Create a unique name for the flag combination
    QString cname;
    cname += QLatin1String("Qt5QWindow");
    switch (type) {
    case Qt::Tool:
        cname += QLatin1String("Tool");
        break;
    case Qt::ToolTip:
        cname += QLatin1String("ToolTip");
        break;
    case Qt::Popup:
        cname += QLatin1String("Popup");
        break;
    default:
        break;
    }
    if (style & CS_DROPSHADOW)
        cname += QLatin1String("DropShadow");
    if (style & CS_SAVEBITS)
        cname += QLatin1String("SaveBits");
    if (style & CS_OWNDC)
        cname += QLatin1String("OwnDC");
    if (icon)
        cname += QLatin1String("Icon");

    return registerWindowClass(cname, qWindowsWndProc, style, GetSysColorBrush(COLOR_WINDOW), icon);
}

Qt一个整个application会维护一个消息处理器,是通过一个windows窗口实现的消息传递QWindowsMessageWindowClassContext
每一个QWidget窗口(子控件不算)也会维护一个windows窗口,来处理系统窗口消息,如下图所示。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看出,所有的窗口走的都是这个窗口消息处理函数。这里回调用到const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result, &platformWindow);在这里面将消息插入到Qt自己的消息队列中,然后wakeup(postMessage唤醒消息)到消息分发窗口,也就是最开始提到的QWindowsMessageWindowClassContext中维护的那个窗口函数。这里有点骚,可以通过句柄获取窗口。
在这里插入图片描述

应用程序之所以没有终止,是因为一直在等待并处理消息
在这里插入图片描述
在这里面从消息队列中拿消息,然后处理
在这里插入图片描述
这里面维护着一个消息队列
在这里插入图片描述

四、总结

这里用一个时序图来清晰化这个流程:
QWidget或每个继承QWidget的窗口

Windows操作系统 QWidget对象 主线程processEvents 鼠标进入窗口消息 在qWindowsWndProc中将消息塞到消息队列,通知主线程处理消息 从消息队列中取消息,并调用对应的QWidget对象处理消息 Windows操作系统 QWidget对象 主线程processEvents
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

parkseyoung

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值