視窗功能

本概觀討論視窗的功能,例如視窗類型、狀態、大小和位置。

視窗類型

本節包含下列描述視窗類型的主題。

重迭的視窗

重迭視窗是最上層視窗, (具有標題列、框線和工作區的非子視窗) ;它的目的是做為應用程式的主視窗。 它也可以有視窗功能表、最小化和最大化按鈕,以及捲軸。 用來作為主視窗的重迭視窗通常包含所有這些元件。

藉由在CreateWindowEx函式中指定WS_OVERLAPPEDWS_OVERLAPPEDWINDOW樣式,應用程式會建立重迭的視窗。 如果您使用 WS_OVERLAPPED 樣式,視窗會有標題列和框線。 如果您使用 WS_OVERLAPPEDWINDOW 樣式,視窗會有標題列、調整大小框線、視窗功能表,以及最小化和最大化按鈕。

快顯視窗

快顯視窗是一種特殊類型的重迭視窗,用於出現在應用程式主視窗外部的對話方塊、訊息方塊和其他暫存視窗。 快顯視窗的標題列是選擇性的;否則,快顯視窗與 WS_OVERLAPPED 樣式的重迭視窗相同。

您可以在CreateWindowEx中指定WS_POPUP樣式,以建立快顯視窗。 若要包含標題列,請指定 WS_CAPTION 樣式。 使用 WS_POPUPWINDOW 樣式來建立具有框線和視窗功能表的快顯視窗。 WS_CAPTION樣式必須與WS_POPUPWINDOW樣式結合,才能顯示視窗功能表。

子視窗

子視窗具有WS_CHILD樣式,而且僅限於其父視窗的工作區。 應用程式通常會使用子視窗,將父視窗的工作區分割成功能區域。 您可以在CreateWindowEx函式中指定WS_CHILD樣式,以建立子視窗。

子視窗必須有父視窗。 父視窗可以是重迭的視窗、快顯視窗,甚至是另一個子視窗。 當您呼叫 CreateWindowEx時,您可以指定父視窗。 如果您在CreateWindowEx中指定WS_CHILD樣式,但未指定父視窗,系統就不會建立視窗。

除非明確要求子視窗,否則子視窗具有工作區,但沒有其他功能。 應用程式可以要求標題列、視窗功能表、最小化和最大化按鈕、子視窗的框線和捲軸,但子視窗不能有功能表。 如果應用程式指定功能表控制碼,則當它註冊子視窗類別或建立子視窗時,會忽略功能表控制碼。 如果未指定框線樣式,系統會建立無框線視窗。 應用程式可以使用無框線子視窗來分割父視窗的工作區,同時讓使用者看不到分割區。

本節討論子視窗的下列層面:

定位

系統一律會將子視窗放置在相對於其父視窗工作區左上角的位置。 子視窗沒有任何部分出現在其父視窗的框線之外。 如果應用程式建立大於父視窗或放置子視窗的子視窗,讓部分或所有子視窗延伸超過父視窗的框線,系統就會裁剪子視窗;也就是說,不會顯示父視窗工作區以外的部分。 影響父視窗的動作也會影響子視窗,如下所示。

父視窗 子視窗
終結 在父視窗終結之前終結。
Hidden 隱藏父視窗之前隱藏。 只有在父視窗可見時,才會顯示子視窗。
使用父視窗的工作區移動。 子視窗負責在移動之後繪製其工作區。
顯示 顯示父視窗之後顯示。

 

裁剪

系統不會從父視窗的工作區自動裁剪子視窗。 這表示如果父視窗在與子視窗相同的位置執行任何繪圖,則會在子視窗上繪製。 不過,如果父視窗具有 WS_CLIPCHILDREN 樣式,系統會從父視窗的工作區裁剪子視窗。 如果剪下子視窗,父視窗就無法繪製它。

子視窗可以重迭相同工作區中的其他子視窗。 與一個或多個其他子視窗共用相同父視窗的子視窗稱為 同層級視窗。 同層級視窗可以繪製在彼此的工作區中,除非其中一個子視窗具有 WS_CLIPSIBLINGS 樣式。 如果子視窗具有此樣式,則會裁剪位於子視窗內的任何同層級視窗部分。

如果視窗具有 WS_CLIPCHILDRENWS_CLIPSIBLINGS 樣式,則效能會稍微遺失。 每個視窗都會佔用系統資源,因此應用程式不應該不小心使用子視窗。 為了達到最佳效能,需要以邏輯方式分割主視窗的應用程式應該在主視窗的視窗程式中執行此動作,而不是使用子視窗。

與父視窗的關聯性

應用程式可以呼叫 SetParent 函式來變更現有子視窗的父視窗。 在此情況下,系統會從舊父視窗的工作區中移除子視窗,並將它移至新父視窗的工作區。 如果 SetParent 指定 Null 控制碼,桌面視窗就會變成新的父視窗。 在此情況下,子視窗會繪製在桌面上,超出任何其他視窗的框線。 GetParent函式會擷取子視窗父視窗的控制碼。

父視窗會將其工作區的一部分重新配置給子視窗,而子視窗會接收此區域的所有輸入。 對於父視窗的每個子視窗,視窗類別不需要相同。 這表示應用程式可以使用看起來不同的子視窗填入父視窗,並執行不同的工作。 例如,對話方塊可以包含許多類型的控制項,每一個子視窗都會接受使用者不同類型的資料。

子視窗只有一個父視窗,但父視窗可以有任意數目的子視窗。 接著,每個子視窗都可以有子視窗。 在這個視窗鏈結中,每個子視窗稱為原始父視窗的子系視窗。 應用程式會使用 IsChild 函式來探索指定的視窗是否為子視窗或指定父視窗的子系視窗。

EnumChildWindows函式會列舉父視窗的子視窗。 然後, EnumChildWindows 會將控制碼傳遞給每個子視窗至應用程式定義的回呼函式。 也會列舉指定父視窗的子系視窗。

訊息

系統會將子視窗的輸入訊息直接傳遞至子視窗;訊息不會透過父視窗傳遞。 唯一的例外狀況是 ,如果 EnableWindow 函式已停用子視窗。 在此情況下,系統會改為將任何已移至子視窗的輸入訊息傳遞給父視窗。 這可讓父視窗檢查輸入訊息,並視需要啟用子視窗。

子視窗可以有唯一的整數識別碼。 使用控制視窗時,子視窗識別碼很重要。 應用程式會藉由傳送訊息來指示控制項的活動。 應用程式會使用控制項的子視窗識別碼,將訊息導向控制項。 此外,控制項會將通知訊息傳送至其父視窗。 通知訊息包含控制項的子視窗識別碼,父代會使用此識別碼來識別傳送訊息的控制項。 應用程式會將CreateWindowEx函式的hMenu參數設定為值,而不是功能表控制碼,以指定其他類型的子視窗識別碼。

分層式 Windows

使用分層視窗可以大幅改善具有複雜圖案的視窗效能和視覺效果、製作其圖案的動畫效果,或想要使用 Alpha 混合效果。 系統會自動撰寫並重新繪製分層視窗和基礎應用程式的視窗。 因此,分層視窗會順暢地轉譯,而不會閃爍複雜的視窗區域。 此外,分層視窗可以是半透明,也就是 Alpha 混合。

若要建立分層視窗,請在呼叫CreateWindowEx函式時指定WS_EX_LAYERED擴充視窗樣式,或在建立視窗之後呼叫SetWindowLong函式來設定WS_EX_LAYERED在 CreateWindowEx呼叫之後,除非為此視窗呼叫SetLayeredWindowAttributesUpdateLayeredWindow函式,才會顯示分層視窗。

注意

從Windows 8開始,WS_EX_LAYERED可以搭配子視窗和最上層視窗使用。 舊版 Windows 僅支援最上層視窗 WS_EX_LAYERED

 

若要設定指定分層視窗的不透明度層級或透明度色彩索引鍵,請呼叫 SetLayeredWindowAttributes。 呼叫之後,系統仍可能會要求視窗在視窗顯示或調整大小時繪製。 不過,由於系統會儲存分層視窗的影像,因此系統不會要求視窗在桌面上移動相對視窗而顯示其部分時繪製。 如果繼承應用程式想要為視窗新增透明或透明度效果,則不需要重新建構其繪製程式碼,因為系統會將呼叫 SetLayeredWindowAttributes 的視窗繪製重新導向至螢幕外記憶體,並重新編譯它以達到所需的效果。

如需更快速且更有效率的動畫,或如果需要每圖元 Alpha,請呼叫 UpdateLayeredWindowUpdateLayeredWindow 主要用於應用程式必須直接提供分層視窗的圖形和內容,而不需使用系統透過 SetLayeredWindowAttributes提供的重新導向機制。 此外,使用 UpdateLayeredWindow 會更有效率地使用記憶體,因為系統不需要儲存重新導向視窗映射所需的額外記憶體。 如需動畫視窗的最大效率,請呼叫 UpdateLayeredWindow 來變更分層視窗的位置和大小。 請注意,呼叫 SetLayeredWindowAttributes 之後,後續的 UpdateLayeredWindow 呼叫將會失敗,直到清除分層樣式位並再次設定為止。

分層視窗的點擊測試是以視窗的形狀和透明度為基礎。 這表示視窗的區域會以色彩索引鍵或 Alpha 值為零的區域,讓滑鼠訊息通過。 不過,如果分層視窗具有 WS_EX_TRANSPARENT 延伸視窗樣式,則會忽略分層視窗的形狀,並將滑鼠事件傳遞至分層視窗底下的其他視窗。

Message-Only Windows

僅限訊息視窗可讓您傳送和接收訊息。 它不可見、沒有迭置順序、無法列舉,也不會接收廣播訊息。 視窗只會分派訊息。

若要建立僅限訊息的視窗,請在CreateWindowEx函式的 hWndParent參數中指定現有訊息專用視窗的HWND_MESSAGE常數或控制碼。 您也可以在SetParent函式的hWndNewParent參數中指定HWND_MESSAGE,將現有的視窗變更為僅限訊息的視窗。

若要尋找僅限訊息的視窗,請在FindWindowEx函式的hwndParent參數中指定HWND_MESSAGE。 此外,如果hwndParenthwndChildAfter參數都是NullFindWindowEx會搜尋僅限訊息的視窗和最上層視窗。

視窗關聯性

視窗有許多方式可以與使用者或另一個視窗產生關聯。 視窗可以是擁有的視窗、前景視窗或背景視窗。 視窗也有相對於其他視窗的迭置順序。 如需詳細資訊,請參閱下列主題:

前景和背景視窗

每個進程可以有多個執行緒執行,而且每個執行緒都可以建立視窗。 建立使用者目前運作之視窗的執行緒稱為前景執行緒,而視窗稱為 前景視窗。 所有其他執行緒都是背景執行緒,而背景執行緒所建立的視窗稱為 背景視窗

每個執行緒都有一個優先順序層級,可決定執行緒接收的 CPU 時間量。 雖然應用程式可以設定其執行緒的優先順序層級,但前景執行緒的優先順序層級通常比背景執行緒高一點。 因為其優先順序較高,所以前景執行緒會收到比背景執行緒更多的 CPU 時間。 前景執行緒的一般基底優先順序為 9;背景執行緒的一般基底優先順序為 7。

使用者按一下視窗,或使用 ALT+TAB 或 ALT+ESC 按鍵組合來設定前景視窗。 若要擷取前景視窗的控制碼,請使用 GetForegroundWindow 函式。 若要檢查應用程式視窗是否為前景視窗,請將 GetForegroundWindow 傳回的控制碼與應用程式視窗的控制碼進行比較。

應用程式會使用 SetForegroundWindow 函式來設定前景視窗。

系統會限制哪些進程可以設定前景視窗。 只有當下列狀況時,進程才能設定前景視窗:

  • 下列所有條件都成立:
    • 呼叫SetForegroundWindow的程式屬於傳統型應用程式,而不是針對 Windows 8 或 8.1 設計的 UWP 應用程式或 Windows 市集應用程式。
    • 前景進程尚未停用對 SetForegroundWindow 的呼叫,前一次呼叫 LockSetForegroundWindow 函式。
    • 前景鎖定逾時已過期, (請參閱SystemParametersInfo) 中的SPI_GETFOREGROUNDLOCKTIMEOUT
    • 沒有作用中的功能表。
  • 此外,至少下列其中一個條件成立:
    • 呼叫進程是前景進程。
    • 呼叫進程是由前景進程啟動。
    • 目前沒有前景視窗,因此沒有前景進程。
    • 呼叫進程收到最後一個輸入事件。
    • 正在偵錯前景進程或呼叫進程。

即使程式符合這些條件,還是可能會拒絕設定前景視窗的許可權。

可以設定前景視窗的進程可以啟用另一個進程來設定前景視窗,方法是呼叫AllowSetForegroundWindow函式,或使用BSF_ALLOWSFW旗標呼叫BroadcastSystemMessage函式。 前景進程可以藉由呼叫LockSetForegroundWindow函式來停用對 SetForegroundWindow的呼叫。

擁有的 Windows

重迭或快顯視窗可以由另一個重迭或快顯視窗所擁有。 擁有會在視窗上放置數個條件約束。

  • 擁有的視窗一律高於其 Z 順序的擁有者。
  • 當擁有者被終結時,系統會自動終結擁有的視窗。
  • 當擁有者最小化時,會隱藏擁有的視窗。

只有重迭或快顯視窗可以是擁有者視窗;子視窗不能是擁有者視窗。 當應用程式建立具有WS_OVERLAPPEDWS_POPUP樣式的視窗時,將擁有者的視窗控制碼指定為CreateWindowExhwndParent參數,以建立擁有的視窗。 hwndParent參數必須識別重迭或快顯視窗。 如果 hwndParent 識別子視窗,系統會將擁有權指派給子視窗的最上層父視窗。 建立擁有的視窗之後,應用程式就無法將視窗的擁有權轉移至另一個視窗。

對話方塊和訊息方塊預設為擁有視窗。 應用程式會在呼叫建立對話方塊或訊息方塊的函式時指定擁有者視窗。

應用程式可以使用 GetWindow 函式搭配 GW_OWNER 旗標來擷取視窗擁有者的控制碼。

Z-Order

視窗的 Z 順序 表示視窗在重迭視窗堆疊中的位置。 此視窗堆疊會沿著虛數軸、Z 軸向外延伸。從螢幕向外延伸。 迭置順序頂端的視窗會與所有其他視窗重迭。 迭置順序底部的視窗會與所有其他視窗重迭。

系統會在單一清單中維護 Z 順序。 它會根據視窗是最上層視窗、最上層視窗或子視窗,將視窗新增至 Z 順序。 最上層視窗與所有其他非最上層視窗重迭,不論它是使用中視窗還是前景視窗。 最上方的視窗具有 WS_EX_TOPMOST 樣式。 所有最上層視窗都會以迭置順序出現在任何非最上層視窗之前。 子視窗會依 z 順序將其父視窗分組。

當應用程式建立視窗時,系統會將它放在相同類型之視窗的 Z 順序頂端。 您可以使用 BringWindowToTop 函式,將視窗帶入相同類型視窗的 z 順序頂端。 您可以使用 SetWindowPosDeferWindowPos 函式來重新排列 Z 順序。

使用者藉由啟動不同的視窗來變更 Z 順序。 系統會將作用中視窗置於相同類型之視窗的 z 順序頂端。 當視窗位於迭置順序頂端時,請執行其子視窗。 您可以使用 GetTopWindow 函式來搜尋父視窗的所有子視窗,並將控制碼傳回至 Z 順序最高的子視窗。 GetNextWindow函式會依 Z 順序擷取下一個或上一個視窗的控制碼。

視窗顯示狀態

在任何指定的時間,視窗可能作用中或非作用中;隱藏或可見;和 最小化、最大化或還原。 這些品質統稱為 視窗顯示狀態。 下列主題討論視窗顯示狀態:

使用中視窗

使用中視窗是使用者目前運作的應用程式最上層視窗。 為了允許使用者輕鬆地識別使用中的視窗,系統會將它放在迭置順序的頂端,並將標題列和框線的色彩變更為系統定義的現用視窗色彩。 只有最上層視窗可以是使用中的視窗。 當使用者使用子視窗時,系統會啟動與子視窗相關聯的最上層父視窗。

系統中只有一個最上層視窗一次處於作用中狀態。 使用者按一下最上層視窗 (或其中一個子視窗) ,或使用 ALT+ESC 或 ALT+TAB 鍵組合來啟動最上層視窗。 應用程式會藉由呼叫 SetActiveWindow 函式來啟動最上層視窗。 其他函式可能會導致系統啟動不同的最上層視窗,包括 SetWindowPosDeferWindowPosSetWindowPlacementDestroyWindow。 雖然應用程式可以隨時啟用不同的最上層視窗,但為了避免混淆使用者,它應該只在回應使用者動作時才會這麼做。 應用程式會使用 GetActiveWindow 函式來擷取使用中視窗的控制碼。

當啟動從某個應用程式的頂層視窗變更到另一個應用程式的最上層視窗時,系統會將 WM_ACTI加值稅EAPP 訊息傳送給這兩個應用程式,通知他們變更。 當啟用變更為相同應用程式中不同的最上層視窗時,系統會將兩個視窗傳送 WM_ACTI加值稅E 訊息。

已停用的 Windows

視窗可以停用。 停用的視窗不會從使用者接收鍵盤或滑鼠輸入,但可以從其他視窗、其他應用程式以及系統接收訊息。 應用程式通常會停用視窗,以防止使用者使用視窗。 例如,應用程式可能會停用對話方塊中的按鈕,以防止使用者選擇按鈕。 應用程式可以隨時啟用停用的視窗;啟用視窗會還原一般輸入。

根據預設,建立時會啟用視窗。 不過,應用程式可以指定 WS_DISABLED 樣式,以停用新的視窗。 應用程式會使用 EnableWindow 函式來啟用或停用現有的視窗。 系統會在啟用狀態即將變更時,將 WM_ENABLE 訊息傳送至視窗。 應用程式可以使用 IsWindowEnabled 函式來判斷視窗是否已啟用。

停用子視窗時,系統會將子系的滑鼠輸入訊息傳遞至父視窗。 父系會使用訊息來判斷是否要啟用子視窗。 如需詳細資訊,請參閱 滑鼠輸入

一次只能有一個視窗可以接收鍵盤輸入;該視窗稱為具有鍵盤焦點。 如果應用程式使用 EnableWindow 函式來停用鍵盤焦點視窗,除了停用之外,視窗也會失去鍵盤焦點。 EnableWindow 接著會將鍵盤焦點設定為 Null,這表示沒有視窗具有焦點。 如果子視窗或其他子系視窗具有鍵盤焦點,則子系視窗會在停用父視窗時失去焦點。 如需詳細資訊,請參閱 鍵盤輸入

視窗可見度

視窗可以顯示或隱藏。 系統會在畫面上顯示 可見的視窗 。 它會隱藏 隱藏的視窗 ,方法是不繪製它。 如果視窗是顯示的,則使用者可以提供輸入至視窗,並檢視視窗的輸出。 如果隱藏視窗,等於是停用視窗。 隱藏視窗能夠處理來自系統或其他視窗的訊息,但是不能處理來自使用者的輸入或顯示輸出。 應用程式會在建立視窗時設定視窗的可見度狀態。 稍後,應用程式可以變更可見度狀態。

視窗設定WS_VISIBLE 樣式時,會顯示視窗。 根據預設,除非應用程式指定WS_VISIBLE樣式,否則 CreateWindowEx函式會建立隱藏的視窗。 一般而言,應用程式會在建立視窗之後設定 WS_VISIBLE 樣式,以保留使用者隱藏建立程式的詳細資料。 例如,當應用程式自訂視窗的外觀時,應用程式可能會隱藏新的視窗。 如果在CreateWindowEx中指定WS_VISIBLE樣式,系統會在建立視窗之後,將WM_SHOWWINDOW訊息傳送至視窗,但在顯示視窗之前。

應用程式可以使用 IsWindowVisible 函式來判斷視窗是否可見。 應用程式可以使用ShowWindow、SetWindowPosDeferWindowPos 或 SetWindowPlacementSetWindowLong函式來顯示) (顯示視窗或隱藏視窗。 這些函式會藉由設定或移除視窗的 WS_VISIBLE 樣式來顯示或隱藏視窗。 它們也會先將 WM_SHOWWINDOW 訊息傳送至視窗,再顯示或隱藏視窗。

當擁有者視窗最小化時,系統會自動隱藏相關聯的擁有視窗。 同樣地,還原擁有者視窗時,系統會自動顯示相關聯的擁有視窗。 在這兩種情況下,系統會在隱藏或顯示 WM_SHOWWINDOW 訊息之前,先將WM_SHOWWINDOW訊息傳送至擁有的視窗。 有時候,應用程式可能需要隱藏擁有的視窗,而不需要最小化或隱藏擁有者。 在此情況下,應用程式會使用 ShowOwnedPopups 函 式。 此函式會設定或移除所有擁有視窗的WS_VISIBLE樣式,並將WM_SHOWWINDOW訊息傳送至擁有的視窗,再隱藏或顯示這些視窗。 隱藏擁有者視窗不會影響擁有視窗的可見度狀態。

當父視窗可見時,也會顯示其相關聯的子視窗。 同樣地,當父視窗隱藏時,其子視窗也會隱藏。 將父視窗最小化不會影響子視窗的可見度狀態;也就是說,子視窗會隨著父視窗一起最小化,但 不會變更WS_VISIBLE 樣式。

即使視窗具有 WS_VISIBLE 樣式,使用者可能無法在畫面上看到視窗;其他視窗可能會完全重迭,或可能已移至螢幕邊緣之外。 此外,可見的子視窗受限於其父子關聯性所建立的裁剪規則。 如果視窗的父視窗不可見,它也不會顯示。 如果父視窗移動超過螢幕邊緣,則子視窗也會移動,因為子視窗是相對於父系左上角繪製的。 例如,使用者可能會移動包含子視窗的父視窗,使其離螢幕邊緣夠遠,使用者可能無法看到子視窗,即使子視窗及其父視窗都有 WS_VISIBLE 樣式。

最小化、最大化和還原的 Windows

最大化視窗是具有WS_MAXIMIZE樣式的視窗。 根據預設值,系統會將最大化視窗放大到佔滿畫面,如果是子視窗,則是放大到佔滿父視窗的工作區 (Client Area)。 雖然視窗的大小可以設定為最大化視窗的大小相同,但最大化的視窗稍微不同。 系統會自動將視窗的標題列移至畫面頂端,或移至父視窗工作區頂端。 此外,系統會停用視窗的大小框線和標題列的視窗定位功能 (,讓使用者無法拖曳標題列) 來移動視窗。

最小化視窗是具有WS_MINIMIZE樣式的視窗。 根據預設值,系統會將最小化的視窗縮小到工作列按鈕的大小,並將最小化的視窗移至工作列。 還原的視窗是已返回其先前大小和位置的視窗,也就是在最小化或最大化之前的大小。

如果應用程式在CreateWindowEx函式中指定WS_MAXIMIZEWS_MINIMIZE樣式,則視窗一開始會最大化或最小化。 建立視窗之後,應用程式可以使用 CloseWindow 函式將視窗最小化。 ArrangeIconicWindows函式會排列桌面上的圖示,或者它會在父視窗中排列父視窗的最小化子視窗。 OpenIcon函式會將最小化的視窗還原為其先前的大小和位置。

ShowWindow函式可以最小化、最大化或還原視窗。 它也可以設定視窗的可見度和啟用狀態。 SetWindowPlacement函式包含與ShowWindow相同的功能,但它可以覆寫視窗的預設最小化、最大化和還原位置。

IsZoomedIsIconic函式會分別判斷指定的視窗是否最大化或最小化。 GetWindowPlacement函式會擷取視窗的最小化、最大化和還原位置,也會決定視窗的顯示狀態。

當系統收到命令以最大化或還原最小化的視窗時,它會傳送視窗 WM_QUERYOPEN 訊息。 如果視窗程式傳回 FALSE,則系統會忽略最大化或還原命令。

系統會自動將最大化視窗的大小和位置設定為最大化視窗的系統定義預設值。 若要覆寫這些預設值,應用程式可以呼叫 SetWindowPlacement 函式,或在系統即將最大化視窗時處理視窗所收到的 WM_GETMINMAXINFO 訊息。 WM_GETMINMAXINFO 包含 MINMAXINFO 結構的指標,其中包含系統用來設定最大化大小和位置的值。 取代這些值會覆寫預設值。

視窗大小和位置

視窗的大小和位置會以周框表示,以相對於螢幕或父視窗的座標來表示。 最上層視窗的座標相對於螢幕左上角;子視窗的座標相對於父視窗的左上角。 應用程式會在建立視窗時指定視窗的初始大小和位置,但可以隨時變更視窗的大小和位置。 如需詳細資訊,請參閱 填滿圖形

本節包含下列主題:

預設大小和位置

應用程式可讓系統藉由在 CreateWindowEx中指定CW_USEDEFAULT來計算最上層視窗的初始大小或位置。 如果應用程式將視窗的座標設定為CW_USEDEFAULT,而且尚未建立其他最上層視窗,則系統會設定相對於畫面左上角的新視窗位置;否則,它會設定相對於應用程式最近建立的最上層視窗位置的位置。 如果寬度和高度參數設定為CW_USEDEFAULT,則系統會計算新視窗的大小。 如果應用程式已建立其他最上層視窗,系統會根據應用程式最近建立的最上層視窗大小來建立新視窗的大小。 在建立子視窗或快顯視窗時指定CW_USEDEFAULT會導致系統將視窗的大小設定為預設的最小視窗大小。

追蹤大小

系統會維護 WS_THICKFRAME 樣式視窗的最小和最大追蹤大小;具有此樣式的視窗具有調整大小框線。 最小追蹤大小是您可以藉由拖曳視窗的大小調整框線所產生的最小視窗大小。 同樣地, 追蹤大小上限 是您可以藉由拖曳調整大小框線所產生的最大視窗大小。

當系統建立視窗時,視窗的最小和最大追蹤大小會設定為系統定義的預設值。 應用程式可以藉由處理 WM_GETMINMAXINFO 訊息來探索預設值並加以覆寫。 如需詳細資訊,請參閱 大小和位置訊息

系統命令

具有視窗功能表的應用程式可以藉由傳送系統命令來變更該視窗的大小和位置。 當使用者從視窗功能表選擇命令時,會產生系統命令。 應用程式可以將 WM_SYSCOMMAND 訊息傳送至視窗,以模擬使用者動作。 下列系統命令會影響視窗的大小和位置。

命令 描述
SC_CLOSE 關閉視窗。 此命令會將 WM_CLOSE 訊息傳送至視窗。 視窗會執行清除和終結本身所需的任何步驟。
SC_MAXIMIZE 最大化視窗。
SC_MINIMIZE 將視窗最小化。
SC_MOVE 移動視窗。
SC_RESTORE 將最小化或最大化的視窗還原為其先前的大小和位置。
SC_SIZE 啟動 size 命令。 若要變更視窗的大小,請使用滑鼠或鍵盤。

 

大小和位置函式

建立視窗之後,應用程式可以呼叫數個不同的函式之一來設定視窗的大小或位置,包括SetWindowPlacementMoveWindow、SetWindowPosDeferWindowPos SetWindowPlacement 會設定視窗的最小化位置、最大化的位置、還原的大小和位置,以及顯示狀態。 MoveWindowSetWindowPos函式類似;兩者都會設定單一應用程式視窗的大小或位置。 SetWindowPos函式包含一組會影響視窗顯示狀態的旗標;MoveWindow不包含這些旗標。 使用BeginDeferWindowPos、DeferWindowPosEndDeferWindowPos函式,同時設定數個視窗的位置,包括大小、位置、位置以 Z 順序排列,以及顯示狀態。

應用程式可以使用 GetWindowRect 函式來擷取視窗周框的座標。 GetWindowRect 會以視窗左上角和右下角的座標填滿 RECT 結構。 座標相對於螢幕左上角,即使是子視窗也是如此。 ScreenToClientMapWindowPoints函式會將子視窗周框的螢幕座標組應至相對於父視窗工作區的座標。

GetClientRect函式會擷取視窗工作區的座標。 GetClientRect 會填入 RECT 結構,其中包含工作區左上角和右下角的座標,但座標相對於工作區本身。 這表示工作區左上角的座標一律 (0,0) ,而右下角的座標是工作區的寬度和高度。

CascadeWindows函式會重迭桌面上的視窗,或串聯指定父視窗的子視窗。 TileWindows函式會磚桌面上的視窗,或磚指定父視窗的子視窗。

大小和位置訊息

系統會將 WM_GETMINMAXINFO 訊息傳送至即將變更大小或位置的視窗。 例如,當使用者從視窗功能表按一下 [ 移動 ] 或 [ 大小 ],或按一下調整大小框線或標題列時,就會傳送訊息;應用程式呼叫 SetWindowPos 來移動或調整視窗大小時,也會傳送訊息。 WM_GETMINMAXINFO 包含 MINMAXINFO 結構的指標,其中包含視窗的預設最大化大小和位置,以及預設的最小和最大追蹤大小。 應用程式可以藉由處理 WM_GETMINMAXINFO 並設定 MINMAXINFO的適當成員來覆寫預設值。 視窗必須具有 WS_THICKFRAMEWS_CAPTION 樣式才能接收 WM_GETMINMAXINFO。 具有 WS_THICKFRAME 樣式的視窗會在視窗建立程式期間以及移動或調整其大小時收到此訊息。

系統會將 WM_WINDOWPOSCHANGING 訊息傳送至視窗,其大小、位置、位在 Z 順序中的位置,或顯示狀態即將變更。 此訊息包含 WINDOWPOS 結構的指標,指定視窗的新大小、位置、位在 Z 順序中的位置,以及顯示狀態。 藉由設定 WINDOWPOS的成員,應用程式可能會影響視窗的新大小、位置和外觀。

變更視窗的大小、位置、位置,或顯示狀態之後,系統會將 WM_WINDOWPOSCHANGED 訊息傳送至視窗。 此訊息包含 WINDOWPOS 的指標,可通知視窗的新大小、位置、以 Z 順序排列的位置,以及顯示狀態。 設定以WM_WINDOWPOSCHANGED傳遞的WINDOWPOS結構成員不會影響視窗。 必須處理 WM_SIZEWM_MOVE 訊息的視窗必須將 WM_WINDOWPOSCHANGED 傳遞至 DefWindowProc 函式;否則,系統不會將 WM_SIZEWM_MOVE 訊息傳送至視窗。

系統會在建立或調整視窗大小時,將 WM_NCCALCSIZE 訊息傳送至視窗。 系統會使用訊息來計算視窗的工作區大小,以及相對於視窗左上角的工作區位置。 視窗通常會將此訊息傳遞至預設視窗程式;不過,此訊息在自訂視窗的非用戶端區域或保留視窗大小時,用戶端應用程式中可能會很有用。 如需詳細資訊,請參閱 繪製和繪圖

視窗動畫

您可以使用 AnimateWindow 函式來顯示或隱藏視窗時產生特殊效果。 當視窗以這種方式產生動畫時,系統會根據您在 對 AnimateWindow的呼叫中指定的旗標來變換、投影或淡出視窗。

根據預設,系統會使用 滾動動畫。 如此一來,視窗會顯示開啟 (顯示視窗) 或關閉 (隱藏視窗) 。 您可以使用 dwFlags 參數來指定視窗是水準、垂直或對角線滾動。

當您指定 AW_SLIDE 旗標時,系統會使用 投影片動畫。 透過此效果,視窗會顯示在檢視 (顯示視窗) 或移出檢視 (隱藏視窗) 。 您可以使用 dwFlags 參數來指定視窗水準、垂直或對角線投影。

當您指定 AW_BLEND 旗標時,系統會使用 Alpha 混合淡化

您也可以使用 AW_CENTER 旗標讓視窗向內折迭或向外展開。

視窗配置和鏡像

視窗配置會定義文字和 Windows 圖形裝置介面 (GDI) 物件在視窗或裝置內容 (DC) 配置的方式。 某些語言,例如英文、法文和德文,需要由左至右 (LTR) 版面配置。 其他語言,例如阿拉伯文和希伯來文,需要從右至左 (RTL) 版面配置。 視窗配置會套用至文字,但也會影響視窗的其他 GDI 元素,包括點陣圖、圖示、原點的位置、按鈕、串聯樹狀結構控制項的位置,以及水準座標在您向左或向右時增加。 例如,在應用程式設定 RTL 配置之後,原點會放置在視窗或裝置的右邊緣,而代表水準座標的數位會在您向左移動時增加。 不過,並非所有物件都會受到視窗的配置影響。 例如,與視窗沒有關聯之對話方塊、訊息方塊和裝置內容的版面配置,例如中繼檔與印表機 DC,必須個別處理。 本主題稍後會提及這些細節。

視窗函式可讓您在阿拉伯文和希伯來文版本的 Windows 中指定或變更視窗配置。 請注意, 對於具有樣式 CS_OWNDC或具有GM_ADVANCED圖形模式的 DC,不支援變更為 RTL 版面配置 (也稱為鏡像) 。

根據預設,視窗配置會由左至右 (LTR) 。 若要設定 RTL 視窗配置,請使用樣式WS_EX_LAYOUTRTL呼叫CreateWindowEx。 此外,根據預設,子視窗 (,也就是使用WS_CHILD樣式建立的視窗,並在呼叫CreateWindow 或 CreateWindowEx) 時,具有與其父系相同的配置。 若要停用所有子視窗的鏡像繼承,請在CreateWindowEx呼叫中指定WS_EX_NOINHERITLAYOUT。 請注意,鏡像不會由擁有的視窗繼承, (建立的視窗沒有WS_CHILD樣式) ,或是使用 CreateWindowEx中父hWnd參數所建立的視窗設定為Null。 若要停用個別視窗的鏡像繼承,請使用GetWindowLongSetWindowLong處理WM_NCCREATE訊息,以關閉WS_EX_LAYOUTRTL旗標。 此處理除了需要任何其他處理之外。 下列程式碼片段示範如何完成此動作。

SetWindowLong (hWnd, 
               GWL_EXSTYLE, 
               GetWindowLong(hWnd,GWL_EXSTYLE) & ~WS_EX_LAYOUTRTL))

您可以呼叫 SetProcessDefaultLayout (LAYOUT_RTL) ,將預設配置設定為 RTL。 呼叫之後建立的所有視窗都會鏡像,但現有的視窗不會受到影響。 若要關閉預設鏡像,請呼叫 SetProcessDefaultLayout (0) 。

請注意, SetProcessDefaultLayout 只會鏡像視窗的 DC。 若要鏡像任何 DC,請呼叫 SetLayout (hdc,LAYOUT_RTL) 。 如需詳細資訊,請參閱本主題稍後的鏡像裝置內容與視窗無關的討論。

鏡像視窗中的點陣圖和圖示預設也會鏡像。 不過,並非所有專案都應該進行鏡像。 例如,具有文字、商務標誌或類比時鐘的時鐘不應該鏡像。 若要停用點陣圖的鏡像,請使用dwLayout中設定的LAYOUT_BITMAPORIENTATIONPRESERVED位呼叫SetLayout。 若要停用 DC 中的鏡像,請呼叫 SetLayout (hdc,0) 。

若要查詢目前的預設配置,請呼叫 GetProcessDefaultLayout。 成功傳回時, pdwDefaultLayout 包含 LAYOUT_RTL 或 0。 若要查詢裝置內容的版面配置設定,請呼叫 GetLayout。 成功傳回時, GetLayout 會傳回 DWORD,這個 DWORD 會依LAYOUT_RTL和LAYOUT_BITMAPORIENTATIONPRESERVED位的設定來指出版面配置設定。

建立視窗之後,您可以使用 SetWindowLong 函式來變更版面配置。 例如,當使用者將現有視窗的使用者介面語言從阿拉伯文或希伯來文變更為德文時,這是必要的。 不過,變更現有視窗的配置時,您必須使視窗失效並更新視窗,以確保視窗的內容全都繪製在相同的版面配置上。 下列程式碼範例來自視需要變更視窗配置的範例程式碼:

// Using ANSI versions of GetWindowLong and SetWindowLong because Unicode
// is not needed for these calls

lExStyles = GetWindowLongA(hWnd, GWL_EXSTYLE);

// Check whether new layout is opposite the current layout
if (!!(pLState -> IsRTLLayout) != !!(lExStyles & WS_EX_LAYOUTRTL))
{
    // the following lines will update the window layout

    lExStyles ^= WS_EX_LAYOUTRTL;        // toggle layout
    SetWindowLongA(hWnd, GWL_EXSTYLE, lExStyles);
    InvalidateRect(hWnd, NULL, TRUE);    // to update layout in the client area
}

在鏡像中,您應該考慮「接近」和「遠」,而不是「左」和「右」。 無法這麼做可能會導致問題。 在螢幕座標與用戶端座標之間對應時,會發生在鏡像視窗中發生問題的常見程式碼撰寫做法。 例如,應用程式通常會使用類似下列的程式碼在視窗中放置控制項:

// DO NOT USE THIS IF APPLICATION MIRRORS THE WINDOW

// get coordinates of the window in screen coordinates
GetWindowRect(hControl, (LPRECT) &rControlRect);  

// map screen coordinates to client coordinates in dialog
ScreenToClient(hDialog, (LPPOINT) &rControlRect.left); 
ScreenToClient(hDialog, (LPPOINT) &rControlRect.right);

這會導致鏡像發生問題,因為矩形的左邊緣會變成鏡像視窗中的右邊緣,反之亦然。 若要避免這個問題,請將 ScreenToClient 呼叫取代為 MapWindowPoints 的呼叫,如下所示:

// USE THIS FOR MIRRORING

GetWindowRect(hControl, (LPRECT) &rControlRect);
MapWindowPoints(NULL, hDialog, (LPPOINT) &rControlRect, 2)

此程式碼的運作方式是,在支援鏡像的平臺上, MapWindowPoints 會修改為在用戶端視窗鏡像時交換左右點座標。 如需詳細資訊,請參閱 MapWindowPoints的一節。

另一個在鏡像視窗中造成問題的常見做法是使用螢幕座標中的位移,而非用戶端座標來將物件定位在用戶端視窗中。 例如,下列程式碼會使用螢幕座標的差異做為用戶端座標中的 x 位置,在對話方塊中放置控制項。

// OK if LTR layout and mapping mode of client is MM_TEXT,
// but WRONG for a mirrored dialog 

RECT rdDialog;
RECT rcControl;

HWND hControl = GetDlgItem(hDlg, IDD_CONTROL);
GetWindowRect(hDlg, &rcDialog);             // gets rect in screen coordinates
GetWindowRect(hControl, &rcControl);
MoveWindow(hControl,
           rcControl.left - rcDialog.left,  // uses x position in client coords
           rcControl.top - rcDialog.top,
           nWidth,
           nHeight,
           FALSE);

當對話方塊視窗具有由左至右 (LTR) 版面配置和用戶端的對應模式MM_TEXT時,此程式碼就沒問題,因為用戶端座標中的新 x 位置會對應至控制項左邊緣和螢幕座標中的對話方塊差異。 不過,在鏡像對話方塊中,向左和向右反轉,因此您應該改用 MapWindowPoints ,如下所示:

RECT rcDialog;
RECT rcControl;

HWND hControl - GetDlgItem(hDlg, IDD_CONTROL);
GetWindowRect(hControl, &rcControl);

// MapWindowPoints works correctly in both mirrored and non-mirrored windows.
MapWindowPoints(NULL, hDlg, (LPPOINT) &rcControl, 2);

// Now rcControl is in client coordinates.
MoveWindow(hControl, rcControl.left, rcControl.top, nWidth, nHeight, FALSE)

鏡像對話方塊和訊息方塊

對話方塊和訊息方塊不會繼承版面配置,因此您必須明確設定配置。 若要鏡像訊息方塊,請使用[MB_RTLREADING] 選項呼叫MessageBox 或 MessageBoxEx 若要從右至左配置對話方塊,請使用對話方塊範本結構 DLGTEMPLATEEX中的延伸樣式WS_EX_LAYOUTRTL。 屬性工作表是對話方塊的特殊案例。 每個索引標籤都會被視為個別的對話方塊,因此您必須在您想要鏡像的每個索引標籤中包含WS_EX_LAYOUTRTL樣式。

鏡像裝置內容未與視窗相關聯

未與視窗相關聯的 DC,例如中繼檔或印表機 DC,不會繼承版面配置,因此您必須明確設定版面配置。 若要變更裝置內容配置,請使用 SetLayout 函式。

SetLayout函式很少與視窗搭配使用。 一般而言,視窗只會在處理 WM_PAINT 訊息時接收相關聯的 DC。 有時候,程式會呼叫 GetDC來建立視窗的 DC。 不論是哪一種方式,DC 的初始配置都是由 BeginPaintGetDC 根據視窗的WS_EX_LAYOUTRTL旗標來設定。

GetWindowOrgExGetWindowExtExGetViewportOrgExGetViewportExtEx所傳回的值不會受到呼叫SetLayout的影響。

當配置為 RTL 時, GetMapMode 會傳回MM_ANISOTROPIC,而不是傳回 MM_TEXT。 使用 MM_TEXT 呼叫 SetMapMode 將會正常運作;只會影響 GetMapMode 的傳回值。 同樣地,呼叫 SetLayout (hdc,當對應模式MM_TEXT時,LAYOUT_RTL) 會導致回報的對應模式變更為MM_ANISOTROPIC。

視窗解構

一般而言,應用程式必須終結它建立的所有視窗。 它會使用 DestroyWindow 函式執行此動作。 當視窗終結時,如果視窗可見,系統會隱藏視窗,然後移除與視窗相關聯的任何內部資料。 這會使視窗控制碼失效,應用程式無法再使用此控制碼。

應用程式會在建立應用程式之後立即終結它建立的許多視窗。 例如,應用程式通常會在應用程式有足夠的輸入以繼續其工作時終結對話方塊視窗。 應用程式最終會在終止) 之前終結應用程式主視窗 (。

在終結視窗之前,應用程式應該儲存或移除與視窗相關聯的任何資料,而且應該釋放配置給視窗的任何系統資源。 如果應用程式未釋放資源,系統將會釋放應用程式未釋放的任何資源。

終結視窗不會影響視窗建立來源的視窗類別。 仍然可以使用該類別建立新的視窗,而該類別的任何現有視窗仍可繼續運作。 終結視窗也會終結視窗的子代視窗。 DestroyWindow函式會先將WM_DESTROY訊息傳送至視窗,再傳送至其子視窗和子系視窗。 如此一來,所終結視窗的所有子代視窗也會被終結。

當使用者按一下 [關閉] 時,具有視窗功能表的視窗會收到WM_CLOSE訊息。 藉由處理此訊息,應用程式可以在終結視窗之前提示使用者確認。 如果使用者確認應該終結視窗,應用程式可以呼叫 DestroyWindow 函式來終結視窗。

如果終結的視窗是使用中視窗,作用中狀態和焦點狀態都會傳輸至另一個視窗。 成為使用中視窗的視窗是下一個視窗,由 ALT+ESC 按鍵組合所決定。 然後,新的使用中視窗會決定哪一個視窗接收鍵盤焦點。