多文檔介面 (MDI) 應用程式中的每個檔案都會顯示在應用程式主視窗工作區內的個別子視窗中。 一般的 MDI(多文件介面)應用程式包括文字處理應用程式,可讓使用者同時處理多個文本文件,以及可讓使用者同時處理多個圖表和試算表的電子試算表應用程式。 如需詳細資訊,請參閱下列主題。
視窗框架 (Frame)、客戶端 (Client) 和子視窗 (Child Windows)
MDI 應用程式有三種視窗:框架視窗、MDI 用戶端視窗,以及一些子視窗。 框架視窗 就像應用程式的主視窗:它有重設大小框線、標題列、視窗功能表、最小化按鈕和最大化按鈕。 應用程式必須註冊框架視窗的視窗類別,並提供視窗程式來支援它。
MDI 應用程式不會在框架窗口的客戶區域中顯示輸出。 相反地,它會顯示 MDI 用戶端視窗。 MDI 用戶端視窗 是一種屬於預先註冊的視窗類別 MDICLIENT的特殊子視窗類型。 用戶端視窗是框架視窗的子系;它會做為子視窗的背景。 它也支援建立及操作子視窗。 例如,MDI 應用程式可以藉由將訊息傳送至 MDI 用戶端視窗來建立、啟動或最大化子視窗。
當使用者開啟或建立檔時,用戶端視窗會建立檔的子視窗。 用戶端視窗是應用程式中所有 MDI 子視窗的父視窗。 每個子視窗都有調整大小的邊框、標題列、視窗功能表、最小化按鈕和最大化按鈕。 因為子視窗已裁剪,所以會受限於客戶端視窗,而且無法出現在其外部。
MDI 應用程式可以支援一種以上的檔。 例如,典型的電子錶格應用程式可讓用戶同時使用圖表和電子表格。 針對它支援的每個檔案類型,MDI 應用程式必須註冊子窗口類別,並提供視窗程式來支援屬於該類別的視窗。 如需視窗類別的更多資訊,請參閱 視窗類別。 若要了解更過關於視窗程序的資訊,請參閱 視窗程式。
以下是典型的 MDI 應用程式。 它名為 Multipad。
子視窗建立
若要建立子視窗,MDI 應用程式會呼叫 CreateMDIWindow 函式,或將 WM_MDICREATE 訊息傳送至 MDI 用戶端視窗。 建立 MDI 子視窗更有效率的方式是呼叫 CreateWindowEx 函式,並指定 WS_EX_MDICHILD 擴充樣式。
若要終結子視窗,MDI 應用程式會將 WM_MDIDESTROY 訊息傳送至 MDI 用戶端視窗。
子視窗啟用
任何數目的子視窗都可以在任何一次出現在客戶端視窗中,但只有一個可以作用中。 作用中的子視窗位於所有其他子視窗的前面,其框線被加亮。
用戶可以按下它來啟動非使用中的子視窗。 MDI 應用程式會將 WM_MDIACTIVATE 訊息傳送至 MDI 用戶端視窗,以啟動子視窗。 當客戶端視窗處理此訊息時,它會將 WM_MDIACTIVATE 訊息傳送至將被啟動的子視窗的視窗程序,以及將被停用的子視窗的視窗程序。
為了防止子視窗被啟動,請處理子視窗的 WM_NCACTIVATE 訊息並傳回 FALSE。
系統會追蹤每個子視窗在重疊視窗堆疊中的位置。 此堆疊稱為 Z-Order。 使用者可以單擊活動視窗功能表中的 [下一步] [下一步],以 Z 順序啟動下一個子視窗。 應用程式會藉由將 WM_MDINEXT 訊息傳送至客戶端視窗,以 Z 順序啟動下一個 (或上一個) 子視窗。
若要取得活動的子視窗的句柄,MDI 應用程式會將 WM_MDIGETACTIVE 訊息傳送至客戶端視窗。
多個文件選單
MDI 應用程式的主視窗應該包含具有視窗選單的選單列。 視窗選單應該包含用於在用戶端視窗內排列子視窗或關閉所有子視窗的項目。 一般 MDI 應用程式的視窗選單可能包含下表中的專案。
| 選單項目 | 目的 |
|---|---|
| 瓷磚 | 以磚格式排列子視窗,讓每個視窗在用戶端視窗中全部顯示。 |
| Cascade | 以串聯格式排列子視窗。 子視窗彼此重疊,但每個視窗的標題列都可見。 |
| 排列圖示 | 沿著客戶端視窗底部排列最小化子視窗的圖示。 |
| 關閉所有 | 關閉所有子視窗。 |
每當建立子視窗時,系統就會自動將新的功能表項附加至視窗功能表。 功能表項的文字與新子視窗功能表欄上的文字相同。 按兩下選單項,使用者可以啟動對應的子視窗。 當子視窗被銷毀時,系統會自動從視窗功能表中移除對應的功能表項。
系統最多可以將十個功能表項新增至視窗功能表。 系統在建立第十個子視窗時,會將 「更多視窗」 項目新增至視窗功能表。 點擊此項目會顯示 [選取視窗] 對話框。 對話框包含清單框,其中包含目前可用的所有 MDI 子視窗標題。 用戶可以按下清單框中的標題來啟動子視窗。
如果您的 MDI 應用程式支援數種類型的子視窗,請量身打造功能表欄,以反映與使用中視窗相關聯的作業。 若要這樣做,請為應用程式支援的每個子窗口類型提供個別的功能表資源。 啟動新類型的子視窗時,應用程式應該將 WM_MDISETMENU 訊息傳送至客戶端視窗,並將句柄傳遞給對應的功能表。
當沒有任何子視窗存在時,選單列應該只包含用來建立或開啟文件的項目。
當使用者使用游標鍵流覽 MDI 應用程式的功能表時,索引鍵的行為會不同於使用者流覽一般應用程式的功能表時。 在 MDI 應用程式中,控制權會從應用程式的視窗選單傳遞至使用中子視窗的視窗選單,然後傳遞至選單欄上的第一個項目。
多文件加速器
若要接收及處理其子視窗的快速鍵,MDI 應用程式必須在其訊息迴圈中包含 translateMDISysAccel函式。 循環必須先呼叫 TranslateMDISysAccel,才能呼叫 TranslateAccelerator 或 DispatchMessage 函式。
MDI 子視窗視窗視窗功能表上的快速鍵與非 MDI 子視窗的快速鍵不同。 在 MDI 子視窗中,ALT+ – (減號) 按鍵組合會開啟視窗選單,CTRL+F4 按鍵組合會關閉使用中的子視窗,而 CTRL+F6 按鍵組合會啟動下一個子視窗。
子視窗的大小與排列設定
MDI 應用程式會將訊息傳送至 MDI 用戶端視窗,以控制其子視窗的大小和位置。 為了最大化作用中的子視窗,應用程式會將 WM_MDIMAXIMIZE 訊息傳送至客戶端視窗。 當子視窗最大化時,其工作區會完全填滿 MDI 用戶端視窗。 此外,系統會自動隱藏子視窗的標題列,並將子視窗的視窗功能表圖示和 [還原] 按鈕新增至 MDI 應用程式的功能表列。 應用程式可以藉由將用戶端視窗傳送 WM_MDIRESTORE 訊息,將客戶端視窗還原為其原始的(預先設定)大小和位置。
MDI 應用程式可以使用串聯或磚格式排列其子視窗。 當子視窗呈現階梯式排列時,視窗會出現在堆疊中。 堆疊底部的視窗佔據螢幕左上角,而其餘視窗則在垂直和水平上錯位,以便每個子視窗的左邊框和標題列可見。 若要以串聯格式排列子視窗,MDI 應用程式會傳送 WM_MDICASCADE 訊息。 一般而言,當使用者在視窗選單上按一下 [ 串聯] 時,應用程式就會傳送此訊息。
當子視窗被平鋪顯示時,系統會完整顯示每個子視窗,不會重疊任何視窗。 所有視窗都會視需要調整為符合客戶端視窗的大小。 若要以磚格式排列子視窗,MDI 應用程式會將 WM_MDITILE 訊息傳送至客戶端視窗。 一般而言,當使用者按兩下視窗選單上 的 [磚] 時,應用程式就會傳送此訊息。
MDI 應用程式應該為它支援的每個子視窗類型提供不同的圖示。 應用程式會在註冊子視窗類別時指定圖示。 當子視窗最小化時,系統會自動在用戶端視窗的下半部顯示子視窗的圖示。 MDI 應用程式會將 WM_MDIICONARRANGE 訊息傳送至用戶端視窗,指示系統排列子視窗圖示。 一般而言,當使用者按兩下視窗選單上 的 [排列圖示] 時,應用程式就會傳送此訊息。
圖示標題視窗
因為 MDI 子視窗可能會被最小化,因此 MDI 應用程式必須避免像操作一般 MDI 子視窗一樣操作圖示標題視窗。 當應用程式列舉 MDI 用戶端視窗的子視窗時,會出現圖示標題視窗。 不過,圖示標題視窗與其他子視窗不同,因為它們是由 MDI 子視窗所擁有。
若要判斷子視窗是否為圖標標題視窗,請使用具有GW_OWNER索引的 GetWindow 函式。 非標題視窗會傳回 NULL。 請注意,此測試不足以用於最上層視窗,因為功能表和對話框是擁有的視窗。
子窗口數據
因為子視窗數目會根據用戶開啟的檔數目而有所不同,因此MDI 應用程式必須與每個子窗口產生關聯數據(例如,目前檔案的名稱)。 有兩種方式可以執行這項作:
- 將子視窗資料儲存在窗口結構中。
- 使用窗口屬性。
窗口結構
當 MDI 應用程式註冊視窗類別時,它可能會為這個特定視窗類別特定的應用程式數據,在視窗結構中保留額外的空間。 若要在此額外空間中儲存和擷取數據,應用程式 會使用 getWindowLong 和 SetWindowLong 函式。
若要保存子視窗的大量數據,應用程式可以分配記憶體來存放數據結構,然後將該結構所屬的記憶體句柄儲存到與子視窗相關聯的額外空間中。
窗口屬性
MDI 應用程式也可以使用視窗屬性來儲存每份檔案的數據。 個別文件資料 是特定子視窗中所包含檔類型的特定數據。 屬性不同於窗口結構中的額外空間,您在註冊窗口類別時不需要配置額外的空間。 視窗可以有任意數目的屬性。 此外,當偏移量用來存取視窗結構中的額外空間時,屬性以字串名稱來引用。 如需更多視窗屬性的資訊,請參閱 視窗屬性。