如何建立精靈

精靈是一種屬性表類型,可提供簡單且強大的方法來引導使用者完成程式。

精靈是簡化用戶體驗的其中一個金鑰。 它們可讓您進行複雜的作業,例如應用程式的設定,並將其分成一系列簡單的步驟。 在程式中的每個時間點,您可以提供所需內容的說明,並顯示可讓使用者進行選取並輸入文字的控制件。

精靈實際上是屬性表的類型。 屬性表基本上是頁面集合的容器,其中每個頁面都是個別的對話框。 雖然一般屬性表可讓用戶隨時存取任何頁面,但精靈會依序顯示頁面。 按鈕會用來向前和向後巡覽,而不是索引標籤。 頁面顯示的順序是由應用程式所控制,而且可以根據使用者輸入加以修改。

精靈的主要樣式有兩種:舊版Wizard97樣式,以及 Windows Vista 中引進的 Aero 樣式。 如需圖例,請參閱 關於屬性表。 (第三個樣式,只使用PSH_WIZARD或PSH_WIZARD_LITE旗標,呈現一個簡單的屬性表序列,沒有標題或浮浮。

注意

精靈內容中的「浮浮浮水印」是出現在部分頁面左邊界的點陣圖。

 

本檔大部分的討論都假設您為具有 5.80 版或更新版本通用控件的系統實作精靈。 如果您嘗試搭配舊版通用控件使用Wizard97樣式,您的應用程式可能會進行編譯,但不會正確顯示。 如需如何在舊版系統上建立Wizard97相容精靈的討論,請參閱本主題稍後的回溯相容精靈。

您需要知道的事項

技術

必要條件

  • C/C++
  • Windows 使用者介面程序設計

指示

精靈實作

實作精靈類似於實作一般屬性表。 在最基本的層級,在定義屬性表的 PROPSHEETHEADER 結構中設定下列其中一個旗標或旗標組合。

旗標 樣式
PSH_WIZARD 沒有標頭或點陣圖的簡單精靈。
PSH_WIZARD_LITE 類似於PSH_WIZARD,外觀有一些微差異:例如,按鈕上方的分隔符會設定為視窗的完整寬度。
PSH_WIZARD97 具有 (選擇性) 標頭、標頭位圖和浮水印的Wizard97精靈。
PSH_WIZARD |PSH_AEROWIZARD 航空精靈。 航空精靈不會使用浮浮浮 它們需要單個線程 Apartment (STA) 模型。

 

實作精靈的基本程式如下:

  1. 為每個頁面建立對話框範本。
  2. 為每個頁面建立 PROPSHEETPAGE 結構,以定義頁面。 此結構會定義頁面,並包含對話框範本的指標,以及任何點陣圖或其他資源。
  3. 上一個步驟中建立的 PROPSHEETPAGE 結構傳遞至 CreatePropertySheetPage 函式,以建立頁面的 HPROPSHEETPAGE 句柄。
  4. 為精靈建立 PROPSHEETHEADER 結構來定義精靈。
  5. PROPSHEETHEADER 結構傳遞至 PropertySheet 函式以顯示精靈。
  6. 針對每個頁面實作對話框程式,以處理來自頁面控件和精靈按鈕的通知訊息,以及處理其他 Windows 訊息。

建立對話框範本

精靈頁面有兩種基本類型:外部和內部。 外部頁面是簡介(歡迎)和完成頁面。 所有其他頁面都是內部頁面。

外部頁面對話框範本

簡介和完成頁面的基本版面配置完全相同。 下圖顯示範例Wizard97簡介頁面,其中包含佔位符浮水印。

screen shot showing a wizard page with a graphic on the left, title and body text on the right, and back, next and cancel buttons at the bottom

對於Wizard97外部頁面,對話框範本為317x193對話框單位。 除了底部包含BackNextCancel 按鈕的 標題 和帶外,它會填滿所有精靈。 保留給「浮浮浮水印」位圖之範本左側不應包含任何控件。 浮水印是在精靈的 PROPSHEETHEADER 結構中指定,而且會自動新增至頁面。 設計資源範本時,您必須為它提供空間。

當您建立浮浮浮圖時,請記住,如果使用者選擇大型系統字型,對話方塊可能會增加大小。 不同的語言也傾向於有不同的字型計量。 當頁面成長時,保留給浮水印的區域會按比例增加。 不過,您無法變更浮浮浮水印位圖,也不會將點陣圖伸展以填滿較大的區域。 相反地,位圖會保留在保留區域左上角的原始大小中。 浮浮浮水印未涵蓋之較大保留區域的一部分會自動填滿位圖左上方圖元的色彩。

如果您需要針對不同的字型計量使用不同的大小浮浮浮水印點陣圖,有兩個可能的解決方案如下:

  • 在建立精靈之前取得字型計量,並指定適當大小的浮浮浮浮浮圖。
  • 當您建立精靈時,請勿指定浮 Wizard97 會將浮浮水印區域保留空白。 然後在保留給浮浮浮浮水印的區域上繪製適當大小的點陣圖。

您可以像一般對話框一樣,將控件放在浮水印右邊的區域。 此區域的背景色彩是由系統決定,而且您不需要採取任何動作。 您通常會在此區域中放置兩個靜態控件。 上方會保留標題,並使用大粗體字型 (12 點 Verdana Bold for Wizard97)。 另一個用於說明文字的另一個會使用標準對話框字型。

簡介和完成頁面的主要差異在於精靈按鈕和靜態控件中的文字。 簡介頁面通常會有 [下一] 和 [上頁] 按鈕,只啟用 [下一步] 按鈕。 完成頁面已啟用 [上一頁] 按鈕,[下一] 按鈕會取代為 [完成] 按鈕。

注意

在 [航空精靈] 中,[一頁] 按鈕會取代為 標題 列中的箭號按鈕。

 

您可以傳送精靈PSM_SETFINISHTEXT訊息,以修改 [完成] 按鈕上的文字。 根據預設,[ 完成] 按鈕不包含鍵盤快捷方式。 若要定義鍵盤快捷方式,請在您傳遞至PSM_SETFINISHTEXT的文字字串中包含 ampersand。 例如,“&Finish” 會將 'F' 定義為鍵盤快捷方式。

內部頁面對話框範本

內部頁面的外觀與外部頁面有些不同。 下圖顯示具有佔位元標頭點圖的範例Wizard97內部頁面。

screen shot of a wizard page with title and subtitle text and a graphic at the top, text in the middle, and buttons on the bottom

頁面頂端的頁首區域是由屬性表處理,因此不會包含在範本中。 標頭的內容會指定於頁面的 PROPSHEETPAGE 結構和精靈的 PROPSHEETHEADER 結構中。 由於內部頁面必須符合頁首與按鈕之間的大小,因此Wizard97對話框範本是317x143對話框單位,比外部頁面的範本小一些。

下圖顯示從相同範本建立的「航空精靈」。

screen shot that differs from the previous one by having a title area at the top, and only next and cancel buttons at the bottom

定義精靈頁面

建立對話框範本和相關資源,例如點陣圖和字串數據表之後,您可以建立屬性表頁面。 此程式與標準屬性表的程序類似。 首先,填入 PROPSHEETPAGE 結構的適當成員 (有些成員是精靈特有的。然後呼叫 CreatePropertySheetPage 函式來建立頁面的 HPROPSHEETPAGE 句柄。

下列精靈相關旗標可以在 PROPSHEETPAGE 結構的 dwFlags 成員設定。

旗標 描述
PSP_HIDEHEADER 在Wizard97中設定外部頁面的這個旗標。 標頭未顯示,而且可以顯示浮水印。
PSP_USEHEADERTITLE 針對內部頁面設定此旗標,以將標題放在Wizard97的頁首區域,或在Aero Wizard 的工作區頂端。
PSP_USEHEADERSUBTITLE 為內部頁面設定此旗標,以在Wizard97的頁首區域中放置副標題。

 

如果您已設定PSP_USEHEADERTITLE或PSP_USEHEADERSUBTITLE,請將標題和副標題文字分別指派給 pszHeaderTitle 和 pszHeaderSubtitle 成員。 當您將文字字串指派給 PROPSHEETPAGEPROPSHEETHEADER 結構的成員時,您可以指派字串指標,或使用MAKEINTRESOURCE宏從字串資源指派值。 字串資源會從精靈 PROPSHEETHEADER 結構之 hInstance 成員中指定的模組載入。

當您呼叫 CreatePropertySheetPage 來建立頁面時,請將結果指派給 HPROPSHEETPAGE 句柄數位的專案。 建立屬性表時會使用此陣列。 頁面句柄的陣列索引會決定其顯示的預設順序。 建立頁面的 HPROPSHEETPAGE 句柄之後,您可以重複使用相同的 PROPSHEETPAGE 結構,藉由將新值指派給相關成員來建立下一頁。

建立頁面的替代方式是針對每個頁面使用不同的 PROPSHEETPAGE 結構,並建立結構的數位。 建立屬性表時,會使用此陣列,而不是 HPROPSHEETPAGE 句柄的陣列。 使用不同的 PROPSHEETPAGE 結構,就不需要呼叫 CreatePropertySheetPage,但會使用更多記憶體。 否則,這兩種方法之間沒有明顯的差異。

下列範例會將值指派給 PROPSHEETPAGE 結構,以定義內部Wizard97頁面。 在此範例中,頁面的標題、子標題和對話框範本都是由其資源識別碼所識別。 接著會呼叫 CreatePropertySheetPage 函式,以建立頁面的 HPROPSHEETPAGE 句柄。 因為它是要出現的第二個頁面,所以句柄會指派給控 點陣列,ahpsp,索引為 1。

// g_hInstance is the global HINSTANCE of the application.
// IntPage1DlgProc is the dialog procedure for this page.
// ahpsp is an array of HPROPSHEETPAGE handles.

PROPSHEETPAGE psp = { sizeof(psp) };

psp.hInstance         = g_hInstance;
psp.dwFlags           = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
psp.lParam            = (LPARAM) &wizdata;
psp.pszHeaderTitle    = MAKEINTRESOURCE(IDS_TITLE1);
psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_SUBTITLE1);
psp.pszTemplate       = MAKEINTRESOURCE(IDD_INTERIOR1);
psp.pfnDlgProc        = IntPage1DlgProc;

ahpsp[1] = CreatePropertySheetPage(&psp);

自訂頁面數據

當您建立頁面時,您可以使用 PROPSHEETPAGE 結構的 lParam 成員,將自定義數據指派給它,通常是將指標指派給使用者定義結構。

第一次選取頁面時,其對話框程式會收到 WM_INITDIALOG 訊息。 訊息的 lParam 值會指向頁面的 PROPSHEETPAGE 結構複本,您可以從中擷取自定義數據。 接著,您可以使用 SetWindowLongPtr 搭配 GWL_USERDATA 做為索引參數,將此資料儲存在後續訊息中。 多個頁面可以有相同數據的指標,而且一個頁面對另一頁所做的任何變更都可供對話程式中的其他頁面使用。

定義Wizard屬性表

如同一般屬性表,您可以填入 PROPSHEETHEADER 結構的成員來定義精靈的屬性表。 此結構可讓您指定組成精靈的頁面及其顯示的預設順序,以及數個相關參數。 接著,您可以呼叫 PropertySheet 函式來啟動精靈。

在Wizard97樣式中,會忽略 PROPSHEETHEADER結構的 pszCaption成員。 相反地,精靈會顯示目前頁面對話框範本中指定的 標題。 如果範本缺少 標題,則會顯示上一頁中的 標題。 因此,若要在所有頁面上顯示相同的 標題,請在簡介頁面的範本中指定 標題。

在 [航空精靈] 樣式中,對話框 標題 取自 pszCaption

如果您已為頁面建立 HPROPSHEETPAGE 句柄的陣列,請將數位指派給 phpage 成員。 如果您已改為建立 PROPSHEETPAGE 結構的陣列,請將陣列指派給ppsp成員,並在 dwFlags 成員中設定PSH_PROPSHEETPAGE旗標。

下列範例會將值指派給 pshPROPSHEETHEADER 結構,並呼叫 PropertySheet 函式來啟動精靈。 Wizard97 樣式精靈同時具有浮浮水印和標頭圖形,由其資源識別元指定。 ahpsp 陣列包含所有 HPROPSHEETPAGE 句柄,並定義其顯示的預設順序。

// g_hInstance is the global HINSTANCE of the application.
// ahpsp is an array of HPROPSHEETPAGE handles.

PROPSHEETHEADER psh = { sizeof(psh) };

psh.hInstance      = g_hInstance;
psh.hwndParent     = NULL;
psh.phpage         = ahpsp;
psh.dwFlags        = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
psh.pszbmHeader    = MAKEINTRESOURCE(IDB_BANNER);
psh.nStartPage     = 0;
psh.nPages         = 4;

PropertySheet(&psh);

對話框程式

精靈的每個頁面都需要一個對話框程式來處理 Windows 訊息,特別是來自其控件和精靈的通知。 幾乎所有精靈都必須能夠處理的三則訊息是WM_INITDIALOGWM_DESTROYWM_NOTIFY。

頁面顯示之前收到WM_NOTIFY 訊息,以及按兩下任何精靈的按鈕時。 訊息的 lParam 參數是 NMHDR 標頭結構的指標。 通知的標識碼包含在結構的 程式代碼 成員中。 大多數精靈需要處理的四個通知如下。

代碼 描述
PSN_SETACTIVE 在頁面顯示之前傳送。
PSN_WIZBACK 按兩下 [上一頁] 按鈕時傳送。
PSN_WIZNEXT 按兩下 [ 下一步] 按鈕時傳送。
PSN_WIZFINISH 按兩下 [ 完成] 按鈕時傳送。

 

處理WM_INITDIALOG和WM_DESTROY

第一次顯示頁面時,其對話框程式會收到 WM_INITDIALOG 訊息。 處理此訊息可讓精靈執行任何必要的初始化工作,例如儲存自定義數據或設定字型。

當屬性表終結時,您會收到 WM_DESTROY 訊息。 系統會自動終結精靈,但處理此訊息可讓您執行任何必要的清除。

處理PSN_SETACTIVE

每次頁面即將顯示時,都會傳送PSN_SETACTIVE通知碼。 第一次瀏覽頁面時,PSN_SETACTIVE遵循 WM_INITDIALOG 訊息。 如果頁面後續重新流覽,則只會收到PSN_SETACTIVE通知。 此通知通常會處理以初始化頁面的數據,並啟用適當的按鈕。

根據預設,精靈會顯示 [上一步]、[下一步] 和 [取消] 按鈕,並啟用所有按鈕。 若要停用按鈕或顯示 [完成],而不是 [下一步],您必須傳送PSM_SETWIZBUTTONS訊息。 傳送此訊息之後,即使已選取新頁面,仍會保留按鈕的狀態,直到其他 PSM_SETWIZBUTTONS 訊息修改為止。 一般而言,所有 PSN_SETACTIVE 處理程式都會傳送此訊息,以確保每個頁面都有正確的按鈕狀態。

您可以隨時使用此訊息變更按鈕狀態。 例如,您可能想要一開始停用 [ 下一步 ] 按鈕。 在使用者輸入所有必要的信息之後,您可以傳送另一則PSM_SETWIZBUTTONS訊息,以啟用 [下一] 按鈕,讓使用者繼續進行下一頁。

下列代碼段會 使用 PropSheet_SetWizButtons 宏,在顯示內部頁面上啟用 [上 一頁] 和 [下一步 ] 按鈕。

case WM_NOTIFY :
    {
        LPNMHDR pnmh = (LPNMHDR)lParam;
        
        switch(pnmh->code)
        {
        
        ...
        
        case PSN_SETACTIVE :
        
            ...
            
            // This is an interior page.
            PropSheet_SetWizButtons(hwnd, PSWIZB_NEXT | PSWIZB_BACK);
            
            ...
        }
    ...
    
    }

處理PSN_WIZNEXT、PSNWIZBACK 和PSN_WIZFINISH

按兩下 [下一步] 或 [上一步] 按鈕時,您會收到PSN_WIZNEXTPSN_WIZBACK通知碼。 根據預設,精靈會自動依建立屬性表時定義的順序,移至下一頁或上一頁。 處理這些通知的常見原因是防止使用者切換頁面,或覆寫預設頁面順序。

若要防止使用者切換頁面,請處理按鈕通知、呼叫 SetWindowLong 函式,並將DWL_MSGRESULT值設定為 –1,並傳回 TRUE 例如:

case PSN_WIZNEXT :

        ...
        
        // Do not go to the next page yet.
        SetWindowLong(hwnd, DWL_MSGRESULT, -1);
        
        return TRUE;
        
        ...

若要覆寫標準順序並移至特定頁面,請呼叫 SetWindowLong,並將 DWL_MSGRESULT 值設定為頁面的資源標識符,並傳回 TRUE。 例如:

case PSN_WIZNEXT :

        ...
        
        // Go straight to the completion page.
        SetWindowLong(hwnd, DWL_MSGRESULT, IDD_FINISH);
        
        return TRUE;
        
        ...

按兩下 [完成] 或 [取消] 按鈕時,您會分別收到PSN_WIZFINISHPSN_RESET通知碼。 按兩下其中一個按鈕時,系統會自動終結精靈。 不過,如果您需要在精靈終結之前執行清除工作,您可以處理這些通知。 若要防止當您收到PSN_WIZFINISH通知時終結精靈,請呼叫 SetWindowLong,並將DWL_MSGRESULT值設定為 TRUE,並傳回 TRUE。 例如:

case PSN_WIZFINISH :

        ...
        
        // Not finished yet.
        SetWindowLong(hwnd, DWL_MSGRESULT, TRUE);
        
        return TRUE;
        
        ...

回溯相容精靈

上一節假設您為具有 第 5 版或更新版本通用控件的系統實作精靈。

如果您要為具有舊版通用控件的系統撰寫精靈,將無法使用上一節中討論的許多功能。 只有通用控件第 5 版和更新版本才支援 Wizard97 樣式所使用的 PROPSHEETHEADER PROPSHEETPAGE 結構成員。 不過,仍可實 作回溯相容 精靈,其外觀與Wizard97樣式類似。 若要這樣做,您必須明確地實作下列專案:

  • 將浮浮浮水印圖形新增至您的簡介和完成頁面的對話框範本。
  • 讓所有範本的大小都相同。 內部頁面沒有個別的系統定義頁首區域。
  • 在您的範本上明確建立內部頁面的頁首區域。
  • 請勿使用標頭圖形,因為如果精靈變更大小,它可能會與標題或副標題衝突。

如需回溯相容精靈的進一步討論,請參閱 回溯相容精靈 97

備註

如需Wizard97設計問題的完整討論,請參閱 Windows SDK 中其他地方的Wizard97規格。 本檔提供對話框維度、點陣圖維度和色彩,以及控件位置等專案的指導方針。

使用屬性表

Windows 通用控件示範 (CppWindowsCommonControls)