Window 中窗口的層次關係以及窗口的屬性【整理】

Window 窗口層次關係
  相信在Window 下面編程的很多兄弟們都不是很清楚Window 中窗口的層次關係是怎麼樣的,這個東西很久已經研究過一下,後來又忘記了,今天又一次遇到了這個問題,所以便整理一下。下面就說說Window 中桌面(Deskkop)以及頂層窗口,以及子窗口之間的關係。
  
  在Window 的圖形界面下,最基本顯示信息的元素就是窗口,每一個Window 窗口都管理着自己與其他窗口之間的關係和自身的一些信息,如:是否可見,窗口的所有者,窗口的父/子關係等等信息,當窗口創建、銷燬、顯示的時候,就會用到這些信息。
  
  在每一個窗口實例中,有四個元素被窗口管理器用來建立窗口管理鏈表。
 

  Child : 指向窗口子窗口的句柄
  Parent 指向窗口父窗口的句柄
  Owner 指向窗口所有者的句柄
  Next:  指向下一個同屬窗口的句柄
  
  衆所周知當Window 初始化的時候,它創建桌面這個窗口,桌面覆蓋着整個窗口,窗口管理器用這個窗口作爲窗口鏈表中第一個元素。因此桌面在窗口的層次關係中在最上層。
  
  在窗口層次關係中,桌面窗口下一層窗口叫做頂層窗口,頂層窗口就是那些不是子窗口的窗口,頂層窗口不能夠有WS_CHILD 屬性。窗口管理器是如何把桌面窗口和頂層窗口聯繫起來的呢?窗口管理器把頂層窗口都組織到一個鏈表中,而這個鏈表的頭存儲的就是桌面窗口的子窗口句柄,每一個子窗口通過Next 就可以找到鏈表中下一個窗口了。這個鏈表被稱爲子窗口鏈表,在同一個子窗口鏈表中的窗口是互爲同屬窗口,所有頂層窗口都是同屬窗口。窗口在子窗口鏈表中的次序,也表明了窗口距離距離桌面窗口的距離。頂層窗口所形成的子窗口鏈表構成了一個Z 軸,窗口管理器就是根據Z 序列來覺得窗口的哪一部分是顯示的,哪一部分是被遮蓋的。
  
  所有頂層窗口的父窗口都是指向桌面窗口的,這樣一來頂層窗口就好像是桌面窗口的子窗口,所有頂層窗口構成的鏈表是桌面窗口的子窗口鏈表。當頂層窗口創建的時候,窗口管理器把頂層窗口放在Z 軸的頂上,這樣使得整個窗口可見,窗口管理器把窗口插入到桌面窗口子窗口鏈表的前面。WS_EX_TOPMOST 這個屬性控制着窗口管理器創建頂層窗口,窗口管理器把沒有WS_EX_TOPMOST 屬性的窗口放在具有WS_EX_TOPMOST 屬性的窗口的後面,這樣就使得具有WS_EX_TOPMOST 屬性的窗口一直顯示在前面。
  

  在頂層窗口之間還有另外一直關係,擁有或者屬於其他的頂層窗口,屬於其他窗口的窗口叫做歸屬窗口,擁有其他窗口叫做宿主窗口,在Z 軸中,歸屬窗口一定在他的宿主窗口的前面,如果一個宿主窗口最小化,那麼歸屬他的窗口會隱藏掉,如果宿主窗口隱藏起來,歸屬他的窗口不會被隱藏掉。如果有三個窗口ABC A 擁有 BB 擁有 C ,如果A 最小化,那麼B 會隱藏,但是 C 還是可見的。怎麼才能夠在窗口之間建立所有關係呢?方法是在調用CreateWindow或者CreateWindowEx 創建窗口的時候,指定hwndParent 參數。
  

  桌面窗口是在窗口層次中的第一層,頂層窗口在窗口層次中的第二層,子窗口也就是那些創建的時候指定了WS_CHILD 屬性的窗口占據了窗口層次的其他層。窗口和子窗口之間的聯繫,就像桌面窗口和頂層窗口之間的關係一樣。

  
  戶區域,所有同一個窗口的子窗口同樣建立一個Z 軸,這個和頂層窗口是類似的,頂層窗口也是顯示在其父窗口――桌面窗口的客戶區域。
  
  16 位和32 位窗口系統的區別
  窗口之間的父子關係、歸屬所有關係、以及根據 Z 軸來顯示的這些規則在16 位和32 位窗口系統中都是相同的。這樣可以是在兩種窗口系統中高度的兼容。兩種窗口系統的區別在於安全和多線程。
  
  Window Nt 在原有的窗口層次關係中多增加了一層,每一個運行着Window NT 的系統中都有一個Window 工作站對象,這個對象是安全對象的第一層,是所有用戶安全對象的繼承之源,每一個Window 工作站對象可以擁有一些桌面對象,每一個桌面都擁有上面描述的那樣的窗口關係。Window Nt 用了兩個桌面窗口對象,一個是用來處理登陸界面、屏蔽、鎖住工作站等,一個是我們登陸之後進來操作的窗口了。J 通常用戶是不能夠創建和刪除桌面的,不過那是通常,實際上在Window 下面也可以實現類似 Linux 中的多個桌面的效果,每一個桌面都是一個獨立的世界。
  
  兩種窗口系統還有兩位一個區別,在16 位窗口系統中不支持多線程,所以應用程序開發者在創建窗口的時候不必考慮線程的問題了。而在32 位窗口系統中由於又支持了窗口的父子關係,歸屬與擁有關係,同一個窗口下面的所有線程都擁有相同的一個輸入隊列,應用程序開發者應該明白輸入隊列是共享的,在同一個時刻只能有一個線程處理消息,其他的線程都在等待輸入隊列一直到GetMessage 或者PeekMessage 返回,而且必須注意的是父窗口和子窗口或者是歸屬與擁有窗口共用同一個線程。
  
  在32 窗口系統中定義兩種新的窗口類型,前臺窗口和背景窗口,這兩種窗口沒有列到窗口的層次關係中,前臺窗口就是用戶當前操作的窗口,其他的所有窗口都是背景窗口。 32 位窗口系統中支持兩個函數來處理前臺窗口SetForegroundWindow GetForegroundWindow
  
  操作窗口列表
  下面是窗口列表操作的一些函數:
  
  
EnumChildWindows
  
  使用這個函數得到一個窗口的所有子窗口,包括子窗口的子窗口。不過在列舉的過程中這個函數不能夠列出正在創建的或者銷燬的窗口。
  
  
EnumThreadWindows
  
  使用這個函數可以列出所有屬於這個線程的窗口。在這個函數調用之後創建的窗口是不能夠被列舉出來的。
  
  
EnumWindows
  
  使用這個函數列舉出所有頂層窗口,不能夠列舉出子窗口,要列出所有的頂層窗口,使用這個函數比GetWindow安全。使用GetWindow 來列出所有的窗口,可能會導致程序無限循環,因爲在調用GetWindow 的過程中,可能一些窗口已經銷燬了。EnumWindows 不能夠列舉出調用這個函數之後創建的頂層窗口。
  
  
FindWindow
  
  可以使用這個函數通過類名或者使用窗口的標題來找到頂層窗口,這個函數不能夠用來找子窗口,這個函數不區分參數的大小寫。這個函數在Z軸中尋找窗口,找到了之後,就會返回。
  
  
GetDesktopWindow
  
  得到桌面窗口句柄
  
  
GetNextWindow
  
  使用這個函數得到這個窗口的同屬窗口,在16 位窗口系統中GetNextWindow GetWindow 是兩個不同的函數,在32 位系統中這個函數是通過GetWindow 來實現的。
  
  
GetParent
  
  如果一個窗口存在父窗口,那麼可以通過這個函數得到窗口的父窗口,如果窗口是頂層窗口,則返回其所有者窗口句柄。
  
  
GetThreadDesktop
  
  這個函數用來得到指定線程的所屬的桌面窗口句柄,在win95 win98 下面由於不支持多桌面,每次調用該函數都返回同一個值。
  
  
GetTopWindow
  
  可以用這個函數來得到給定窗口的第一個子窗口的句柄,如果傳遞給函數的參數是NULL 的話,那麼這個函數將會返回最上面的頂層窗口。
  
  
GetWindow
  
  應用程序可以調用這個函數來在窗口列表中導航,這個函數有兩個參數,一個是窗口的句柄,另外是要得到的窗口句柄和這個窗口之間的關係。
  
  · GW_HWNDNEXT: 這個函數返回給定窗口的下一個同屬窗口
  
  · GW_HWNDFIRST: 返回給定窗口的前一個同屬窗口
  
  · GW_HWNDLAST: 返回給定窗口的最後一個同屬窗口
  
  · GW_HWNDPREV: 返回給定窗口的第一個同屬窗口
  
  · GW_OWNER: 返回給定窗口的所有者窗口句柄
  
  · GW_CHILD: 返回給定窗口的第一個子窗口句柄
  
  
IsChild
  這個函數有兩個參數,兩個窗口句柄,判斷兩個窗口是否存在父子關係
  
  窗口的屬性
  當應用程序調用CreateWindow 創建窗口的時候,我們必須爲窗口指定屬性,下面簡要的介紹一下窗口的屬性。
  
  
WS_OVERLAPPED
  交迭屬性是頂層窗口的一種屬性,使用這種屬性創建的窗口,會被鏈接到桌面窗口的子窗口鏈表中,應用程序通常使用這種屬性的窗口作爲應用程序的主窗口,具有交迭屬性的窗口通常具有有標題欄,即使是WS_CAPTION 這個屬性沒有指定。具有交迭屬性的窗口通常都是有邊框的,具有交迭屬性的窗口可以擁有自己的頂層窗口,也可以所屬其他的頂層窗口,所有的這類窗口都具有WS_CLIPSIBLINGS 屬性,即使是沒有給窗口指定這個屬性。
  
  
WS_POPUP
  彈出屬性也是應用到頂層窗口的一種屬性,使用這種屬性創建的窗口會被鏈接到桌面窗口的子窗口鏈表中,應用程序通常爲對話框窗口設置這個屬性,彈出屬性和交迭屬性的主要區別在於具有彈出屬性的窗口不是一定要有標題欄的,而具有交迭屬性的窗口則是一定要具有標題欄,具有彈出屬性的窗口可以沒有邊框。和具有交迭屬性的窗口一樣,具有彈出屬性的窗口可以有自己的頂層所屬窗口,也可以所屬其他的頂層窗口。所有具有彈出屬性的窗口必須具有WS_CLIPSIBINGS 屬性,即使是用戶沒有指定這個屬性。具有彈出屬性的窗口在創建的時候,它的大小和位置不能夠使用CW_USEDEFAULT 值。
  
  WS_CHILD

子窗口必須具有這個屬性,子窗口只能夠出現在父窗口的客戶區域,這是子窗口和具有交迭屬性的窗口以及彈出屬性的窗口的主要區別,創建子窗口的時候,位置和大小不能夠使用CW_USEDEFAULT這個值,否則是不能夠創建窗口的。

WS_CAPTION

 

 當窗口被設置這個屬性的時候,窗口的最上頭會有標題欄,應用程序可以通過SetWindowText這個函數來改變標題欄的標題,通常具有標題欄的窗口還具有最大、最小、關閉按鈕,和系統菜單。如果一個窗口沒有標題欄,那麼Window是不會創建這些東西的,即使是用戶指定了這些屬性,系統菜單是依賴標題欄窗口的存在而存在的,如果沒有標題欄那麼是一定不會有系統菜單的存在的。具有標題欄的窗口通常具有單線的邊界具有可以改變窗口大小的屬性,通常具有標題欄的窗口是不能具有對話框的邊界屬性的,除非爲窗口設置WS_EX_DLGMODALFRAME屬性。 WS_MINIMIZEBOX

 

當爲窗口設置這個屬性的時候,窗口的標題欄上會有一個最小化的按鈕,其實對於Window來實現這個屬性的時候,只是在標題欄上面放置了一個最小化的位圖,當用戶點擊這個最小化位圖的時候,窗口最小化,如果最大化位圖最在,那麼最小化位圖被放置在最大化位圖的左邊。沒有這個屬性的窗口是不能夠最小化的。

WS_MAXIMIZEBOX

 

當爲窗口設置這個屬性的時候,窗口的標題欄的右上會被放置一個最大化的位圖,如果窗口設置了這個屬性,用戶可以點擊最大化的位圖或者是通過系統菜單來實現窗口的最大化,沒有這個屬性的窗口是不能夠被最大化的。

WS_SYSMENU

 

如果爲窗口指定這個屬性,那麼就會在窗口的左上角上放置系統菜單位圖,系統菜單爲用戶提供了操作窗口的接口,通常系統菜單會有下面這些系統命令:

恢復最小化的窗口使用鍵盤移動窗口使用鍵盤改變窗口的大小最小化窗口最大化窗口關閉窗口切換到其他的任務

 

如果一個窗口有系統菜單,用戶可以通過點擊系統菜單圖標來調用系統菜單,或者通過Alt+空格的快捷鍵調出系統菜單,或者通過點擊任務欄上窗口的圖標來調出系統菜單,如果一個窗口沒有系統菜單,那麼用戶不能夠通過鍵盤來實現系統命令,除非應用程序自身提供了這樣的接口。系統菜單對於最大化的窗口也是很有用處的,最大化的窗口覆蓋了整個屏幕,這樣的窗口不能夠被移動,除非恢復到不是最大化的狀態,如果這個最大化的窗口有了系統菜單,則就不必一定恢復到非最大化的狀態才能夠移動。

WS_HSCROLL

 

如果窗口被指定了這個屬性,那麼窗口會有一個水平的滾動條,窗口是不會自動的滾動滾動條的,如果應用程序要支持滾動條,那麼必須自己處理WM_HSCROLL消息,這個屬性通常是在窗口創建的時候,被指定的。 

WS_VSCROLL

 

如果窗口被指定了這個屬性,那麼窗口會有一個豎直的滾動條,窗口不會自動的滾動滾動條,應用程序必須自己處理WM_VSCROOL消息來處理滾動條滾動的消息,這個屬性通常是在窗口被創建的時候指定的。

WS_BORDER

 

如果窗口被指定了這個屬性,那麼窗口會有一個單線的邊在窗口的周圍,如果沒有指定這個屬性,但是窗口具有標題欄,那麼窗口會自動的擁有這個屬性,如果窗口沒有這個屬性,擁有這個屬性的窗口不能夠通過鍵盤或者是鼠標改變窗口的大小。

WS_DLGFRAME

 

如果窗口被指定了這個屬性,那麼窗口具有對話框的邊框,這個屬性通常是用在對話框窗口的,只能夠用在窗口沒有標題欄的情況下,如果一個不是對話框的窗口使用了這個窗口,那麼窗口必須被指定WS_EX_DLGMODALFRAME屬性。使用這個屬性創建的窗口,不能夠通過鍵盤和鼠標改變窗口的大小。

WS_THICKFRAME

 

當窗口被指定了這個屬性,那麼窗口會有一個可以改變大小的邊框,這種屬性通常用在程序的主窗口,具有這種屬性的窗口的大小可以通過鍵盤或者鼠標來改變。

WS_CLIPCHILDREN

 

這個屬性用在具有子窗口的窗口,使用這個屬性,可以使Window把子窗口所佔的區域拷貝到父窗口,而不是甴父窗口直接的畫子窗口所屬的區域,如果窗口沒有指定這個屬性,那麼那麼父窗口會覆蓋子窗口的區域。在一些圖片顯示或者OpenGL顯示的窗口中,指定這個屬性是很重要的。

WS_CLIPSIBLINGS

 

當窗口賦予這個屬性,窗口在自繪的時候,不會繪製到同屬的子窗口,所有具有交迭屬性和彈出屬性的窗口都具有這個屬性,所有的頂層窗口都具有這個屬性,這樣一來頂層窗口在自繪的時候,不會繪製在到其他的頂層窗口。 

WS_VISIBLE

 

當窗口被設置這個屬性的時候,窗口是可見的,默認的情況下,應用程序必須自己調用ShowWindow來顯示窗口。

WS_DISABLED

 

當窗口被設置這個屬性的時候,創建的窗口不能夠接受用戶的輸入,除非應用程序自身提供方法來輸入。這個屬性通常用在Window控件上面。

WS_CHILDWINDOW

 

這個屬性同WS_CHILD

WS_OVERLAPPEDWINDOW

 

這個屬性同WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,這個屬性通常用在應用程序的主窗口。

WS_POPUPWINDOW

 

這個屬性同WS_POPUP|WS_BORDER|WS_SYSMENU,儘管這個屬性中包含了WS_SYSMENU屬性,如果窗口沒有WS_CAPTION屬性,那麼窗口也不會有系統菜單。

WS_EX_DLGMODALFRAME

 

當窗口設置了這個屬性的時候,窗口具有對話框的邊框,這個屬性通常用在對話框窗口,不過任何窗口都可以使用這個屬性來獲得對話框的邊框。

WS_EX_NOPARENTNOTIFY

 

這個屬性是用在子窗口上的,當子窗口設置了這個屬性,Window不發送WM_NOTIFY消息給子窗口的父窗口,默認情況下,Window會在子窗口創建或者銷燬的時候發送WM_NOTIFY消息給子窗口的父窗口。WS_EX_TOPMOST

 

這個屬性僅用在頂層窗口,對於子窗口設置這個屬性是被忽略的,如果窗口設置了這個屬性,那麼窗口會一直在其他窗口的上面。

WS_EX_ACCEPTFILES

 

窗口設置了這個屬性,那麼窗口可以接受拖放的對象。

WS_EX_TRANSPARENT

 

這個屬性能夠使窗口透明,設置了這個屬性的窗口的背景使可以被看到的,透明窗口對於鼠標和鍵盤的消息事件並不是透明的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章