首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

MFC 程式設計師的 WTL 入門指南 (九):屬性頁與精靈對話框完整實作

     編輯:關於VC++

屬性表與精靈:Windows 經典 UI 範式

屬性表 (Property Sheet) 自 Windows 95 起成為選項設定的標準介面;精靈模式則廣泛用於軟體安裝或複雜任務引導。WTL 提供 CPropertySheetImpl/CPropertyPageImpl 完整支援兩種模式,並整合 DDX/DDV 資料交換驗證機制。

核心類別架構

類別角色定義於
CPropertySheetWindow視窗介面類別 (封裝 PSM_* 訊息)atldlgs.h
CPropertySheetImpl完整實作類別 (管理 PROPSHEETHEADER、頁面陣列)
CPropertyPageWindow頁面視窗介面atldlgs.h
CPropertyPageImpl頁面完整實作 (衍生自 CDialogImplBaseT,支援 DDX/DDV)

CPropertySheet/CPropertyPage 為非客製化專用的簡易別名。

關鍵方法速查

CPropertySheetImpl

// 建構式:標題(字串或資源ID)、起始頁索引、父視窗
CPropertySheetImpl(_U_STRINGorID title = NULL, UINT uStartPage = 0, HWND hWndParent = NULL)

BOOL AddPage(HPROPSHEETPAGE hPage)        // 以頁面控制代碼加入
BOOL AddPage(LPCPROPSHEETPAGE pPage)      // 以結構體加入 (內部建立管理)
BOOL RemovePage(HPROPSHEETPAGE hPage)     // 移除頁面
BOOL SetActivePage(HPROPSHEETPAGE hPage)  // 設定作用中頁面
void SetTitle(LPCTSTR lpszText, UINT nStyle = 0) // 設定標題,nStyle=PSH_PROPTITLE 會加上 "Properties for"
void SetWizardMode()                      // 切換為精靈模式 (必須在顯示前呼叫)
void EnableHelp()                         // 啟用說明按鈕 (PSH_HASHELP)
INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) // 模態顯示
HWND Create(HWND hWndParent = NULL)       // 非模態建立

CPropertyPageImpl

CPropertyPageImpl(_U_STRINGorID title = NULL) // 頁籤標題
HPROPSHEETPAGE Create()                     // 手工建立頁面控制代碼
void SetTitle(_U_STRINGorID title)          // 變更頁籤文字
void SetHeaderTitle(LPCTSTR)                // Wizard97 標頭標題
void SetHeaderSubTitle(LPCTSTR)             // Wizard97 標頭副標題
void EnableHelp()                           // 啟用本頁說明按鈕 (PSP_HASHELP)

// 通知訊息處理虛擬函式 (WTL 7 新機制,需定義 _WTL_NEW_PAGE_NOTIFY_HANDLERS)
int OnSetActive()       // 頁面啟動,傳回 0 允許
BOOL OnKillActive()     // 頁面失去焦點,傳回 TRUE 允許
int OnApply()           // 套用按鈕,傳回 PSNRET_NOERROR 成功
void OnReset()          // 取消/重設
BOOL OnQueryCancel()    // 詢問取消,傳回 TRUE 允許
int OnWizardBack()      // 精靈「上一步」
int OnWizardNext()      // 精靈「下一步」
INT_PTR OnWizardFinish()// 精靈「完成」
void OnHelp()           // 說明按鈕

實戰範例:選項屬性表與精靈

專案為 SDI 程式,客戶區顯示圖片與背景色,透過「工具|選項」開啟屬性表,「工具|精靈」開啟精靈。

最簡單屬性表:關於頁面

LRESULT CMainFrame::OnAppAbout(...)
{
    CPropertySheet sheet(_T("About PSheets"));
    CPropertyPage<IDD_ABOUTBOX> pgAbout;
    sheet.AddPage(pgAbout);
    sheet.DoModal();
    return 0;
}

進階屬性頁:背景設定頁 (CBackgroundOptsPage)

class CBackgroundOptsPage :
    public CPropertyPageImpl<CBackgroundOptsPage>,
    public CWinDataExchange<CBackgroundOptsPage>
{
public:
    enum { IDD = IDD_BACKGROUND_OPTS };
    BEGIN_MSG_MAP(CBackgroundOptsPage)
        MSG_WM_INITDIALOG(OnInitDialog)
        CHAIN_MSG_MAP(CPropertyPageImpl<CBackgroundOptsPage>)
    END_MSG_MAP()
    BEGIN_DDX_MAP(CBackgroundOptsPage)
        DDX_RADIO(IDC_BLUE, m_nColor)
        DDX_RADIO(IDC_ALYSON, m_nPicture)
    END_DDX_MAP()
    BOOL OnInitDialog(HWND, LPARAM);
    int OnApply(); // 儲存使用者選擇
    int m_nColor, m_nPicture;
};

int CBackgroundOptsPage::OnApply()
{
    return DoDataExchange(TRUE) ? PSNRET_NOERROR : PSNRET_INVALID;
}

封裝屬性表類別:CAppPropertySheet

class CAppPropertySheet : public CPropertySheetImpl<CAppPropertySheet>
{
public:
    CAppPropertySheet(_U_STRINGorID title = NULL, UINT uStartPage = 0, HWND hWndParent = NULL);
    BEGIN_MSG_MAP(CAppPropertySheet)
        CHAIN_MSG_MAP(CPropertySheetImpl<CAppPropertySheet>)
    END_MSG_MAP()
    CBackgroundOptsPage m_pgBackground;
    CPropertyPage<IDD_ABOUTBOX> m_pgAbout;
};

CAppPropertySheet::CAppPropertySheet(_U_STRINGorID title, UINT uStartPage, HWND hWndParent)
    : CPropertySheetImpl<CAppPropertySheet>(title, uStartPage, hWndParent)
{
    m_psh.dwFlags |= PSH_NOAPPLYNOW; // 隱藏「套用」按鈕
    AddPage(m_pgBackground); AddPage(m_pgAbout);
}

精靈實作:COptionsWizard

class COptionsWizard : public CPropertySheetImpl<COptionsWizard>
{
public:
    COptionsWizard(HWND hWndParent = NULL);
    BEGIN_MSG_MAP(COptionsWizard)
        CHAIN_MSG_MAP(CPropertySheetImpl<COptionsWizard>)
    END_MSG_MAP()
    CWizIntroPage m_pgIntro;
    // 其他頁面:CWizBkColorPage, CWizBkPicturePage, CWizFinishPage
};

COptionsWizard::COptionsWizard(HWND hWndParent)
    : CPropertySheetImpl<COptionsWizard>(0U, 0, hWndParent)
{
    SetWizardMode(); // 關鍵:切換精靈模式
    AddPage(m_pgIntro);
    // AddPage 其他頁面...
}

精靈頁面關鍵處理:OnSetActive / OnKillActive

// 簡介頁:僅啟用「下一步」
int CWizIntroPage::OnSetActive() { SetWizardButtons(PSWIZB_NEXT); return 0; }

// 背景色頁:啟用「上一步/下一步」,OnKillActive 執行 DDV 驗證
int CWizBkColorPage::OnSetActive() { SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT); return 0; }
int CWizBkColorPage::OnKillActive()
{
    if (!DoDataExchange(TRUE)) return TRUE; // DDV 失敗阻止離開
    if (m_bFailDDV) { // 核取方塊勾選時人為阻擋
        MessageBox(_T("Error box checked, wizard will stay on this page."), _T("PSheets"), MB_ICONERROR);
        return TRUE;
    }
    return FALSE; // 允許離開
}

差異:OnKillActive 在「上一步/下一步」皆觸發;OnWizardNext 僅在「下一步」觸發,且可指定跳轉特定頁面。

進階技巧

屬性表置中顯示

預設出現在父視窗左上角。解法:自訂訊息 UWM_CENTER_SHEET,屬性表處理該訊息呼叫 CenterWindow,各頁面 OnInitDialog 發送此訊息。

#define UWM_CENTER_SHEET WM_APP
// 屬性表類別
BEGIN_MSG_MAP(CAppPropertySheet)
    MESSAGE_HANDLER_EX(UWM_CENTER_SHEET, OnPageInit)
    CHAIN_MSG_MAP(CPropertySheetImpl<CAppPropertySheet>)
END_MSG_MAP()
LRESULT OnPageInit(UINT, WPARAM, LPARAM)
{
    if (!m_bCentered) { m_bCentered = true; CenterWindow(m_psh.hwndParent); }
    return 0;
}
// 頁面 OnInitDialog
BOOL CBackgroundOptsPage::OnInitDialog(HWND, LPARAM)
{
    GetPropertySheet().SendMessage(UWM_CENTER_SHEET);
    DoDataExchange(FALSE); return TRUE;
}

頁籤加入圖示

CBackgroundOptsPage::CBackgroundOptsPage()
{
    m_psp.dwFlags |= PSP_USEICONID;
    m_psp.pszIcon = MAKEINTRESOURCE(IDI_TABICON);
    m_psp.hInstance = _Module.GetResourceInstance();
}

頁籤圖示效果

下一章預告

將介紹 WTL 工具類別、GDI 物件封裝與通用對話框。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved