QT源码解析(七)Qt创建窗体的过程,作者“ tingsking18 ”(真正的创建QPushButton是在show()方法中,show()方法又调用了setVisible方法)
前言:分析Qt的代码也有一段时间了,以前在进行QT源码解析的时候总是使用ue,一个函数名在QTDIR/src目录下反复的查找,然后分析函数之间的调用关系,效率实在是太低了,最近总结出一个更简便的方法,就是利用Qt Creator这个IDE。
带来的好处是:
1. Qt Creator可以很方便的跟踪代码的调用,这样大大提高了分析代码的速度。
2. 函数间的调用关系能更加直观的找到。
3. 便于对代码的纵向关系的把握。
带来的坏处:
1. 只是展现了调用到的函数或者类的关系。
2. 缺少对类、某一组类、函数间关系的整体把握。
上面总结一下自己在QT源码解析时候用到的方法,下面开始步入正题。Qt创建窗体的过程,由于我对linux不是很熟悉,下面我所有的分析都是基于windows下的。
关于windows下利用API创建窗体。我这里就不多解释了,直接给出代码,然后结合下面的代码来分析一下Qt创建窗体的过程。
详细的解释请参考:
John Chen大牛的博文:WIN32 SDK界面编程
- #include
- LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
- int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
- PSTR szCmdLine, int iCmdShow)
- {
- static TCHAR szAppName[] = TEXT ("HelloWin") ;
- HWND hwnd ;
- MSG msg ;
- WNDCLASS wc ;
- wc.style = CS_HREDRAW | CS_VREDRAW ;
- wc.lpfnWndProc = WndProc ;
- wc.cbClsExtra = 0 ;
- wc.cbWndExtra = 0 ;
- wc.hInstance = hInstance ;
- wc.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
- wc.hCursor = LoadCursor (NULL, IDC_ARROW) ;
- wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
- wc.lpszMenuName = NULL ;
- wc.lpszClassName = szAppName ;
- if (!RegisterClass (&wc))
- {
- MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ;
- return 0 ;
- }
- hwnd = CreateWindow (szAppName, // window class name
- TEXT (“hello”), // window caption
- WS_OVERLAPPEDWINDOW, // window style
- CW_USEDEFAULT, // initial x position
- CW_USEDEFAULT, // initial y position
- CW_USEDEFAULT, // initial x size
- CW_USEDEFAULT, // initial y size
- NULL, // parent window handle
- NULL, // window menu handle
- hInstance, // program instance handle
- NULL) ; // creation parameters
- ShowWindow (hwnd, iCmdShow) ;
- UpdateWindow (hwnd) ;
- while (GetMessage (&msg, NULL, 0, 0))
- {
- TranslateMessage (&msg) ;
- DispatchMessage (&msg) ;
- }
- return msg.wParam ;
- }
- LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- HDC hdc ;
- PAINTSTRUCT ps ;
- RECT rect ;
- switch (message)
- {
- case WM_PAINT:
- hdc = BeginPaint (hwnd, &ps) ;
- GetClientRect (hwnd, &rect) ;
- DrawText (hdc, TEXT ("the WM_PAINTmessage"), -1, &rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
- EndPaint (hwnd, &ps) ;
- return 0 ;
- case WM_DESTROY:
- PostQuitMessage (0) ;
- return 0 ;
- }
- return DefWindowProc (hwnd, message, wParam, lParam) ;
- }
先写一个最简单的Qt程序:
- #include
- #include
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- QPushButton w("hello kitty");
- w.show();
- return a.exec();
- }
来分析一下这个窗体程序是如何创建的。
首先关于main函数和winmain函数,为什么Qt的窗口程序是用main函数而非winmain,在我的另外一篇博文中有解释:QT源码解析(一) QT创建窗口程序、消息循环和WinMain函数 这里不再解释
Windows窗体创建一定会调用RegisterClass这个函数的,我们在QTDIR/src里面搜索一下,有两个文件有这个函数一个是qapplication_win.cpp另外一个是qeventdispatcher_win.cpp,两个的作用不同,这次我们先研究qapplication_win.cpp中的RegisterClass函数,因为这个是与窗体创建有关的,下一篇QT源码解析(八)Qt是如何处理windows消息的 将会介绍qeventdispatcher_win.cpp中的RegisterClass的作用。
我们先将断点设置在qapplication_win.cpp中的 qt_reg_winclass 函数里,然后开始调试,运行到断点,然后我们看一下call stack如下图:
下面红色的框中为Call stack,我们可以看到函数调用的顺序,真正的创建QPushButton是在show()方法中,show()方法又调用了setVisible方法…… ……
QtWndProc就是窗体的回调函数,在RegisterClass的时候传给WNDCLASS结构的,QtWndProc同上面的API创建窗体的函数WndProc。
我们看一下QtWndProc的代码,也是一个switch (message) 然后一堆case来处理消息,最后也是调用DefWindowProc将不归他处理的消息交还给系统。
http://blog.sina.com.cn/s/blog_a401a1ea0101e75v.html
QT源码解析(七)Qt创建窗体的过程,作者“ tingsking18 ”(真正的创建QPushButton是在show()方法中,show()方法又调用了setVisible方法)的更多相关文章
- QT源码解析(一) QT创建窗口程序、消息循环和WinMain函数
QT源码解析(一) QT创建窗口程序.消息循环和WinMain函数 分类: QT2009-10-28 13:33 17695人阅读 评论(13) 收藏 举报 qtapplicationwindowse ...
- Qt源码解析之-从PIMPL机制到d指针
一.PIMPL机制 PIMPL ,即Private Implementation,作用是,实现 私有化,力图使得头文件对改变不透明,以达到解耦的目的 pimpl 用法背后的思想是把客户与所有关于类的私 ...
- Spring源码解析二:IOC容器初始化过程详解
IOC容器初始化分为三个步骤,分别是: 1.Resource定位,即BeanDefinition的资源定位. 2.BeanDefinition的载入 3.向IOC容器注册BeanDefinition ...
- 谷歌BERT预训练源码解析(三):训练过程
目录前言源码解析主函数自定义模型遮蔽词预测下一句预测规范化数据集前言本部分介绍BERT训练过程,BERT模型训练过程是在自己的TPU上进行的,这部分我没做过研究所以不做深入探讨.BERT针对两个任务同 ...
- Celery 源码解析七:Worker 之间的交互
前面对于 Celery 的分布式处理已经做了一些介绍,例如第五章的 远程控制 和第六章的 Event机制,但是,我认为这些分布式都比较简单,并没有体现出多实例之间的协同作用,所以,今天就来点更加复杂的 ...
- ReactiveSwift源码解析(七) Signal的CombineLatest的代码实现
本篇博客我们就来聊一下combineLatest()的使用以及具体的实现方式.在之前的<iOS开发之ReactiveCocoa下的MVVM>的博客中我们已经聊过combineLatest( ...
- Mybaits 源码解析 (二)----- 根据配置文件创建SqlSessionFactory(Configuration的创建过程)
我们使用mybatis操作数据库都是通过SqlSession的API调用,而创建SqlSession是通过SqlSessionFactory.下面我们就看看SqlSessionFactory的创建过程 ...
- jQuery 源码解析(七) jQuery对象和DOM对象的互相转换
jQuery对象是一个类数组对象,它保存的是对应的DOM的引用,我们可以直接用[]获取某个索引内的DOM节点,也可以用get方法获取某个索引内的DOM节点,还可以用toArray()方法把jQuery ...
- Fabric1.4源码解析:Peer节点背书提案过程
以前从来没有写过博客,从这段时间开始才开始写一些自己的博客,之前总觉得写一篇博客要耗费大量的时间,而且写的还是自己已经学会的,觉得没什么必要.但是当开始用博客记录下来的时候,才发现有些学会的地方只是自 ...
随机推荐
- 4557: [JLoi2016]侦察守卫
4557: [JLoi2016]侦察守卫 链接 分析: 因为D比较小,所设状态f[i][j]表示子树i内,从i往下第j层及第j层以下都覆盖了的最小代价,g[i][j]表示覆盖完子树内所有点,还可以往上 ...
- 微信小程序:选项卡页面切换
一.功能描述 在同一个页面内实现不同展示页面的切换功能,如下图所示 二.代码实现 1. index.js Page({ /** * 页面的初始数据 */ data: { currentData : 0 ...
- intellIJ IDEA配置maven相关问题记录
IntellIJ IDEA 配置 Maven 以及 修改 默认 Repository 参考:https://www.cnblogs.com/phpdragon/p/7216626.html non-m ...
- Closure Compiler应用程序使用入门[译]
Hello World示例 Closure Compiler应用程序是一个Java 命令行工具,用来对JavaScript代码进行压缩.优化和排错.按照下面的步骤,用一个简单的JavaScript程序 ...
- JUC——线程同步锁(LockSupport阻塞原语)
java.util.concurrent.locks.LockSupport这个是一个独立的类,这个类的主要功能是用来解决Thread里面提供的suspend()(挂起线程).resume()(恢复运 ...
- python游戏编程——乌龟和鱼类场景编程
综合举例: 游戏编程:按以下要求定义一个乌龟类和鱼类并尝试编写游戏. O 假设游戏场景为范围(x, y)为0<=x<=10,0<=y<=10 · 游戏生成1只 ...
- oozie捕获标准输出&异常capture-output
对于普通的java-action或者shell-action 都是支持的只要标准输出是"k1=v1"这中格式的就行: 现用test.py进行测试: ##test.py #! /op ...
- Memcached服务器上实现多个实例(约约问题排查)
约约测试服上出行一个问题,司机收车失败. (1)经查看代码是null指针异常. 针对,之前,同套代码发布到华威测试服,未出现该问题,遂认定不是代码问题. (2)打印异常信息,获取null值异常的收车司 ...
- Centos7 Jenkins
代码上线 持续集成 随时随地将代码合并,这种方法叫做持续集成. 持续集成(CONTINUOUS INTEGRATION,简称CI)持续集成指的是,频繁地(一天多次)将代码集成到主干.它的好处主要有两个 ...
- JSBridge实现示例
前言 参考来源 前人栽树,后台乘凉,本文参考了以下来源 Hybrid APP架构设计思路 marcuswestin/WebViewJavascriptBridge 楔子 本文介绍JSBridge的完整 ...