窗口風格是各種窗口開發的重要基礎之一。它可以分為普通風格(WS_系列)和擴展風格(WS_EX_系列)。從其特點上,主要分成兩大類:
1. 一類表明窗口和其它窗口的關系,包括:WS_CHILD、WS_POPUP、WS_OVERLAPPED、WS_CLIPCHILDREN、WS_CLIPSIBLINGS、WS_GROUP、
WS_EX_TOPMOST、WS_EX_MDICHILD等。(這里的關系並不是指Foreground/Background window和Z-Order的概念)
2. 一類表明窗口自身的外觀特征,包括:WS_BORDER、WS_CAPTION、WS_MINIMIZE、WS_MINIMIZEBOX、WS_DLGFRAME、
WS_EX_DLGMODALFRAME 、WS_EX_WINDOWEDGE等。
例如:
一個標准的Dialog窗口,除了Dialog自身的風格(DS_系列)外,其窗口風格如下:
普通風格:WS_CAPTION | WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SYSMENU
擴展風格:WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT | WS_EX_APPWINDOW
一個標准的Frame窗口,其風格如下:
普通風格:WS_CAPTION | WS_OVERLAPPED | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU | WS_MAXIMIZE | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
擴展風格: WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_WINDOWEDGE
大部分的窗口風格都比較容易理解。下面重點講解一下第一類風格中主要幾個風格的差異:
- WS_POPUP和WS_OVERLAPPED的窗口均為top-level窗口,即:如果采用SetWindowPos改變其位置需要使用Screen坐標,而不是Client坐標。不同的是,WS_POPUP窗口有父窗口,使用GetParent方法可以獲得;而WS_OVERLAPPED窗口卻沒有,GetParent方法為NULL。也就是說,對於一個界面應用程序而言,一定存在至少一個WS_OVERLAPPED窗口(作為應用程序的主窗口)。
此外,WS_OVERLAPPED窗口總是有title bar和border,即使你顯示刪除WS_CAPTION和WS_BORDER風格,而WS_POPUP卻沒有該特點。
- WS_CLIPCHILDREN:繪圖時,將該窗口中的子窗口所占的區域排除在外。當你創建父窗口時,可以使用該風格。如果使用Invalidate方法,這部分區域不會計算在更新區域內。因此,有可能產生這些子窗口沒有刷新的問題。
- WS_CLIPSIBLINGS:繪圖時,將該子窗口和其同級其它子窗口(具有相同的父窗口)重疊的區域排除在外。如果使用Invalidate方法,這部分區域不會計算在更新區域內。這樣此時繪畫,就不會畫到其它窗口上。
- WS_EX_APPWINDOW:強迫一個top-level窗口在可見時,出現在TaskBar上。但這並不意味着一個窗口出現在TaskBar上就一定需要該風格,其實,如果是主線程的第一個窗口(m_pMainWnd),即使沒有該風格,也會出現在TaskBar上。
- WS_EX_LAYERED:建立Layered窗口,即:具有復雜視覺特征的窗口,比如:透明窗口。該風格不能用於子窗口。主要有SetLayeredWindowAttributes和UpdateLayeredWindow兩個方法,其中,后者更加靈活。前者通常用來實現透明窗口等簡單任務。
上面提到了top-level窗口,因此有必要解釋下面幾個方法的差異:
GetParent方法:如果是子窗口(具有WS_CHILD風格),那么總能得到一個有效的臨時窗口對象(Immediate Window);如果是top-level窗口,又分為兩種情況:如果該窗口為非擁有(unowned),那么返回NULL,否則,返回擁有者窗口對象。因此,GetParent並非總是返回父窗口。
GetOwner方法:獲得擁有者窗口,默認為父窗口。父子窗口中的子窗口只能出現在父窗口的客戶區域,而具有擁有者窗口的窗口可以出現在桌面的任何位置。這里的Owner窗口,不同於API方法GetWindow獲得的Owner窗口,它是MFC特定的概念。
GetAncestor方法:獲得祖先窗口。有三個選擇,GA_PARENT, GA_ROOT, GA_ROOTOWNER
MFC中的Immediate窗口:在MSDN中關於MFC的描述中,經常能看到Immediate和Permanent Window字樣。其中,Immediate窗口是MFC中臨時產生的窗口對象,MFC會定期清理這些對象,因此通常不可以保存作為類成員變量。
