Qt show背后发生的一些事
Posted unclerunning
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt show背后发生的一些事相关的知识,希望对你有一定的参考价值。
Qt show背后发生的一些事
分析
一个窗口要在操作系统中显示出来,必然要调用操作系统提供的接口。例如在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
以上是关于Qt show背后发生的一些事的主要内容,如果未能解决你的问题,请参考以下文章