Qt show背后发生的一些事
来源:互联网 发布:java 视频断点上传 编辑:程序博客网 时间:2024/06/07 11:13
Qt show背后发生的一些事
- Qt show背后发生的一些事
- 分析
- test1
- test2
- test3
- references
分析
一个窗口要在操作系统中显示出来,必然要调用操作系统提供的接口。例如在window平台上编写界面程序时,程序员需要设计窗口类,向操作系统注册窗口类,创建窗口句柄,显示窗口1
show并没有做什么:
void QWidget::show() { Qt::WindowState defaultState = QGuiApplicationPrivate::platformIntegration()->defaultWindowState( data->window_flags); if (defaultState == Qt::WindowFullScreen) showFullScreen(); else if (defaultState == Qt::WindowMaximized) showMaximized(); else setVisible(true); // FIXME: Why not showNormal(), like QWindow::show()? }
真正创建窗口句柄的任务在setVisible中被调用:
void QWidget::setVisible(bool visible){ if (visible) { // show if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden)) return; Q_D(QWidget); /* 如果该widget的句柄还未被创建,且该窗口是一个独立窗口或者是父窗口 已经创建了窗口句柄的一个非独立窗口,那么就创建一个窗口句柄(对应win32的实现为 注册窗口类和回调过程,创建窗口)。 */ //create toplevels but not children of non-visible parents QWidget *pw = parentWidget(); if (!testAttribute(Qt::WA_WState_Created) && (isWindow() || pw->testAttribute(Qt::WA_WState_Created))) { create(); //调用它创建窗口句柄 } ... /* 如果该widget是一个独立窗口,或者是一个父窗口可见的非独立窗口,就调用 QWidgetPrivate::show_helper()==》showChildren()递归地将它“当前”的子窗口 都显示出来。 */ if (isWindow() || parentWidget()->isVisible()) { d->show_helper(); ... } ...}
就如注释上说的,你直接或间接的调用了setVisible,如果窗口句柄还没有被创建,那就会通过create创建,后面的代码还将递归的创建这个窗口当前的所有子窗口,这就是父窗口一次show就可以将它当前所有子窗口显示出来的原因。
接下来瞧瞧create:
void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow){ Q_D(QWidget); if (Q_UNLIKELY(window)) qWarning("QWidget::create(): Parameter 'window' does not have any effect."); /* 防止重复创建 */ if (testAttribute(Qt::WA_WState_Created) && window == 0 && internalWinId()) return; ... //设置已创建标记 setAttribute(Qt::WA_WState_Created); // set created flag //调用平台相关的实现,创建窗口 d->create_sys(window, initializeWindow, destroyOldWindow); ... }
最终的创建肯定是和平台密切相关的,这一点无法逃避,下面是window平台的实现2:
void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow) { ... //注册窗口类 QString windowClassName = qt_reg_winclass(q); ... //创建窗口 WinAPI id = CreateWindowEx(exsty, reinterpret_cast<const wchar_t *>(windowClassName.utf16()), reinterpret_cast<const wchar_t *>(title.utf16()), style, x, y, w, h, parentw, NULL, appinst, NULL); ... //显示窗口 WinAPI ShowWindow(q->internalWinId(), SW_SHOW); ... }
const QString qt_reg_winclass(QWidget *w) // register window class { ... WNDCLASS wc; wc.style = style; wc.lpfnWndProc = (WNDPROC)QtWndProc; //窗口过程 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = qWinAppInst(); wc.hCursor = 0; HBRUSH brush = 0; if (w && !qt_widget_private(w)->isGLWidget) brush = (HBRUSH)GetSysColorBrush(COLOR_WINDOW); wc.hbrBackground = brush; wc.lpszMenuName = 0; wc.lpszClassName = (wchar_t*)cname.utf16(); ATOM atom = RegisterClass(&wc); //注册窗口类 WinAPI ... return cname; }
接下来是一些小实验:
test1
#include "myclass.h"#include "childwin.h"#include "childwin1.h"#include <QtWidgets/QApplication>int main(int argc, char *argv[]){ QApplication a(argc, argv); MyClass w; childWin cw(&w); childWin1 cw1(&w); w.setVisible(true); return a.exec();}
上面的cw和cw1是w的子窗口,cw和cw1都是继承自QWidget的窗口类并且各自都有一个QLabel的子窗口。代码只对w调用了setVisible,在此之前cw和cw1已在w的孩子窗口链表中且w还未显示出来。按照前面的分析,第一次调用w.setVisible时,他除了将自己的窗口句柄创建并显示出来之外,还会递归将他的所有孩子窗口句柄创建出来并显示。这意味着它会显示,它的孩子会显示,它的孩子的孩子也会显示…实验证实了这个推理:
test2
int main(int argc, char *argv[]){ QApplication a(argc, argv); MyClass w; childWin cw(&w); w.setVisible(true); childWin1 cw1(&w); return a.exec();}
和test1比,test2做了一点小调整,我将cw1对象的创建(注意是对象,不是窗口句柄)放在了w.setVisible之后。这样的调整会带来什么变化呢?哦,那就是w和cw以及cw的所有孩子窗口都被创建和显示但是cw1以及他的孩子窗口都不会被创建和显示。为什么了?因为在w.setVisible调用时,cw1还不在w的孩子链表中。所以递归创建窗口的过程不会涉及cw1。实验结果如下:
test3
int main(int argc, char *argv[]){ QApplication a(argc, argv); MyClass w; childWin cw(&w); //w.setVisible(true); childWin1 cw1(&w); cw.show(); cw1.show(); return a.exec();}
这次,我将w.setVisible注释掉了,然后对cw和cw1分别调用show,期望他们能显示出来。下面运行,结果肯定让你大吃一惊,没有任何窗口显示出来!怎么会这样,代码里明明白白的调用了show,这还能有假吗?
代码不会欺骗人,直觉在欺骗人。由于w是cw和cw1的父窗口,但是作为父窗口的w都还没有创建和显示出来,子窗口怎么会创建和显示出来呢!
void QWidget::setVisible(bool visible){ ... /* 如果该widget的句柄还未被创建,且该窗口是一个独立窗口或者是父窗口 已经创建了窗口句柄的一个非独立窗口,那么就创建一个窗口句柄(对应win32的实现为 注册窗口类和回调过程,创建窗口)。 */ //create toplevels but not children of non-visible parents QWidget *pw = parentWidget(); if (!testAttribute(Qt::WA_WState_Created) && (isWindow() || pw->testAttribute(Qt::WA_WState_Created))) { create(); //调用它创建窗口句柄 }...}
references
- 跟我一起玩Win32开发(2):完整的开发流程 ↩
- qwidget_win.cpp ↩
- Qt show背后发生的一些事
- closesocket()背后发生的事
- 调用closesocket()背后发生的事
- 文件上传所发生的一些事?
- Qt的show和exec的区别
- Qt中使用show函数的注意事项。
- Qt中使用show函数的注意事项。
- Java中new DerivedClass()时背后发生的事情
- 浏览淘宝网页背后所发生的事情
- 今天发生的一些事情
- QT的一些奇葩事
- 关于安装python2.7发生的一些事
- 关于一些网站域名背后的秘密
- Qt show()和exec()
- QT中对话框的show()和exec()的区别
- 对死锁发生的一些建议
- VS2008 发生的一些错误1
- 关于QT 中 QDialog的几点,exec show(ZZ)
- 用 React + es6 完成一个著名的生命游戏(Game of life,Conway)
- MllpDecoderState 源码
- 多态的认识
- Java面向对象笔记(三)this关键字
- 史上最全常用正则表达式
- Qt show背后发生的一些事
- Java面向对象笔记(四)匿名对象
- poj-3261 Milk Patterns 后缀数组简单题
- 滑动开关按钮
- Visual Studio Code 添加设置代码段(snippet)
- Android SharedPreferences存取清删
- 树莓派3b+ 用samba与windows共享文件
- 数据库事务四个特点
- mac上用xcode开发ios 程序时候的一些小技巧(二)