一、背景
万事开头难,前几天花了两天时间终于搭建好了Qt的源码调试环境,认识一个系统,最先要搞清楚的就是消息循环和事件分发机制,这是之后继续深入学习qt的前提,话不多说,直接开撸。
二、代码走读
1.QApplication
相信任何人学习Qt的第一行代码就是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的窗口