本文以一个Win32的helloworld程序开篇,
-
程序入口WinMain
- 注册窗口类别
- 建立窗口,在屏幕上显示
- 进入事件循环,不断从事件队列中取出消息来处理
而后尝试解释前述各部分分别隐藏在Qt何处:
main() | 程序入口 | Qt提供一个WinMain来调用main |
QWidget::show() | 注册窗口类别 | 第一次使用时会注册类别 |
显示窗体 | 和hide、setHidden都是setVisble的马甲 | |
QApplication::exec() | 进入事件循环 | 核心是 QEventDispatcherWin32 |
声明,我对Win32编程不了解,本文只是Qt学习过程中的学习笔记,本文提到内容以及用词描述可能会不太准确。
一个简单的Win32程序
这是Win32编程的一个hello world程序:
-
包含头文件,定义入口函数WinMain
-
创建窗口类别(注意里面的WndProc是我们后面定义的回调函数),并注册窗口类别
- 创建窗体,并显示与更新窗体
- 启动事件循环
以上我们所讨论的都是必要的东西:注册窗口类别,建立窗口,在屏幕上显示窗口,进入事件循环,不断从事件队列中取出消息来处理。
实际的动作发生在消息处理函数中。该函数确定了在视窗的显示区域中显示些什么以及怎样响应用户的输入等。
- 消息处理函数(回调函数)
用cl或gcc编译该程序:
考虑Qt?
既然是 hello world,也就基本是最简单的Win32程序了。但看着还是挺复杂,难怪大家都不怎么喜欢它。
Qt(或其他的图形库/框架)多简单啊,简单几行代码一个程序就出来了。可是... 简单的表象下面呢?我们如何把一个Windows下的 Qt 程序和上面的代码对应上?
-
入口函数 WinMain
在Qt中我们只写main函数,不写WinMain,挺有意思哈,不过在Qt Windows下链接子系统与入口函数(终结版) 中我们已经详细讨论过这个问题了(简单地说:就是qtmain.lib或libqtmain.a提供了一个WinMain,它会调用我们的main)
- 创建并注册窗体类别与创建并显示窗体部分
这个东西挺隐蔽的哈,当你对一个QWidget调用setVisble()或者它的众多马甲(比如show() )之一时,会执行这部分代码。源码位于qwidget_win.cpp 和 qapplication_win.cpp 文件中
- 事件循环
这个循环体现在Qt中就是 QApplication::exec()。核心代码在qeventdispatcher_win.cpp 中。
注册窗体类别
当第一次调用setVisible()时,会进行窗口类别的创建,这最终会调用 qapplication_win.cpp 中的下面一个函数:
恩,和前面的比对一下,应该是一样的吧(注意这儿注册的回调函数函数名:QtWndProc)
附:调用关系:
- QWidget::create()
-
==>QWidgetPrivate::sys_create()
-
==>qt_reg_winclass()
消息处理函数
接前面,不妨直接看看QtWndProc这个回调函数(在同一个文件内), 尽管我们都知道它里面是一个大大的switch语句,我还是贴一点它的代码出来:
注意:里面出现两处msg消息的过滤。可以对照 Manual 看。
- QCoreApplication::filterEvent()
- QWidget::winEvent()
接下来以whell事件为例,看一下Windows事件如果变成Qt中的事件,并进入Qt自身的消息循环的:
通过这个,我们看到:
- 消息函数接受到的消息被封装成相应的QEvent,然后发送到Qt自身的事件循环中。
- 我们可以看到接收事件的对象是如何一步一步被确定的。对于wheel事件:
- 首先是光标下的widget(注意popup widget的处理)
- 如果该widget不接受,则发送到有焦点的widget。
- 通过这儿,我们应该容易理解QWheel中这句话的真实含义了:
事件循环
在 QDialog 模态对话框与事件循环 与 QEventLoop 的使用两例 等blog中,已经对此做过介绍:QApplication::exec()最终将(在一个while循环内)不断调用 qeventdispatcher_win.cpp 文件中的processEvents函数:
这个文件很复杂,此处只摘取了个人感兴趣的片段(其实是因为其他的大段我看不太懂):
-
可以看到win32中熟悉的 PeekMessage、TranslateMessage、DispatchMessage
- 注意用户输入事件和socket通知事件的处理(放入queued队列)
- 注意此处也有一个 filterEvent,和QApplication提供的过滤器比较一下。发现谁更厉害没?
写到到这个地方,似乎从win32到Qt的对比分析已经做完了。恩,我也觉得差不多,只是...
对与 QEventDispatcherWin32 这个东西,我们还有很多话没说。它是事件循环的关键,而且它不止在主线程使用(我们肯定都知道QThread::exec())。
QEventDispatcherWin32补遗
在QTimer源码分析(以Windows下实现为例) 我们提到了它和定时器Timer的密切关系,刚刚又提到它是事件循环的关键,还有一点似乎还需要提一下:
- QApplication 初始化时创建该对象
- 在构造函数中,它创建并注册了一个内部用的窗口类别,而后创建一个窗口。
其回调函数 qt_internal_proc 也在该文件内(略过)
- 在创建内部窗口的同时,它还安装了一个钩子(Hook)
-
在钩子的回调函数中,一些消息被PostMessage到上面提到的内部窗口中
总算大体上理了一遍,尽管很多东西还是不懂。有错误欢迎大家指出哈 dbzhang800 2011.04.28
写的途中发现一个技术大牛 tingsking18 写过这方面的东西了(链接附文后),不过我还是认为自己的更详细一点。
参考
- Programming Windows
-
http://blog.csdn.net/tingsking18/archive/2009/10/28/4737925.aspx