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的時候可以設定的,不同通常用在全屏是,其他情況應該很少用到