Window窗口有很多属性,可以通过设定window的style和ex style中知道。
这些属性有时候在实现某些效果的时候,是非常非常重要(以前都没有怎么详细了解,只是在用到对应的API时看一下,根本没有详细深入)。
这里想记录一下最近工作上遇到的问题,是关于窗口的层次关系或者可以说是彼此之间的包含关系,和窗口控制的经验
首先,需要知道parent和owner之间的区别:
1、如果一个窗口有WS_CHILD属性,那么它一定有一个父窗口,即GetParent()返回的一定是其父窗口;
2、如果一个窗口有WS_CHILD属性,那么它一定不能够是popup/overlap(这两个属性在CreateWindow里面出入,或者使用GetWindowLong/SetWindowlong,GWL_STYLE进行设定)窗口;
3、top-level窗口是指,在桌面下一层的窗口,它只能是popup/overlap窗口;
4、popup/overlap窗口,是top-level窗口,通常popup窗口是我们看到的普通的dialog窗口,而overlap窗口是我们用MFC直接创建的那些single document的窗口;
5、owner窗口只能是top-level窗口,owned窗口也是top-level窗口;
6、GetParent()函数返回的是对应窗口的parent,或者是owner窗口;
7、GetWindow(hWnd, GW_OWNER)返回的只能够是owner窗口,否则就是NULL;
8、要获取真正的parent窗口,逻辑应该这样:UINT style = GetWindowLong(hWnd, GWL_STYLE); return style & WS_CHILD ? GetParent(hWnd) : GetWindow(hWnd, GW_OWNER);
由于以下这篇文章写得实在太好了,我是参考下面得出上面的结论的:
http://www.laho.gov.cn/cjs_new/print.jsp?oldID=34
这个blog也有对窗口属性的详细讲解,我也参考了一些呢:
http://www.cppblog.com/Clouderman/default.html?page=2
然后就是MSDN上的东西也是需要看的:
http://msdn.microsoft.com/en-us/library/ms632599%28v=VS.85%29.aspx
msdn貌似才是最权威的,但上面的那个文章中提及的东西和其中的实验,非常值得一看,看完上面,再看下面,会比较实际,呵呵
如何将一个窗口挂在一个D3D渲染的窗口前面,目前有三种选择:
1、创建owner/owned窗口
由于owned窗口一定在owned窗口前面,所以这个方法是行得通的。window的机制,能够确保:
1) owner窗口渲染完之后,再渲染owned窗口;
2) owner窗口最小化时,owned窗口也一起最小化;
3) owner窗口恢复的时候,owned窗口也一起恢复;
如果你在spy++中查看owner和owned窗口的层次,你会发现他们是在同一层的,owner/owned窗口关系没有parent/child窗口关系强!(详细的看上面的链接,里面有更清楚的描述)。
我这里想说的是,owner/owned窗口,有一个限制条件,就是owner/owned窗口都必须是top-level窗口。这就出问题了:如果我的D3D窗口是某个窗口的子窗口,怎么办呢?那么这时候,就会很容易出现问题了,由于渲染的D3D窗口本身是一个child窗口,十分容易收到父窗口的影响,而你创建的这个owned窗口,是受渲染窗口的父窗口控制的,由于你通常都是拥有渲染窗口的HANDLE,有时候owner窗口做出的操作并不是你想要的!这时候就麻烦了,需要通过检测各种各样的消息避免一些你不想出现的情况。
PS:创建owner/owned窗口的SDK方法是:CreateWindow("mywinclass", "title", WS_POPUP, x, y, w, h, hOwnerWnd, NULL, hInst, NULL); 其中WS_POPUP和hOwnerWnd这里必须要填,WS_POPUP可以是WS_OVERLAPPED属性(因为这样可以创建出一个top-level窗口)
2、parent/child关系的窗口
其实可以将owner/owned看作是一种弱的parent/child关系。所以上面描述的有点,parent/child都有。但parent不需要一定是top-level,所以你的child肯定可以绑定在parent上,而且一定是显示在parent窗口前面,这正是我们想要的。但parent在invalid的时候,会发送repaint消息到child中,由于是D3D窗口(一般在30帧渲染一次,导致窗口invalid),所以一定会导致child窗口不停收到repaint的消息,而出现闪烁的问题。
ms已经想到有这个情况了,所以提供了一个WS_CLIPCHILEDREN的属性,用来设定parent的窗口,这样,parent在invalid的时候,就不会不停地发消息过去了。
所以这里也需要注意了,这个child窗口的渲染,必须你自己来管理,如果你依赖parent窗口invalid的时候刷新的话,那么不好意思,肯定有BUG了
3、top-most窗口
这个不用多说了吧,在SetWindowPos的时候可以设定的,不同通常用在全屏是,其他情况应该很少用到