MFC 專案中實現「屬性頁」或「精靈」介面,核心類別為 CPropertySheet (屬性表/精靈容器) 與 CPropertyPage (單頁)。本文從資源建立、類別產生、精靈模式啟用、按鈕控制、資料驗證、資料回傳到視圖顯示,提供完整實作步驟與關鍵程式碼。
IDD_PROPAGE_LARGE,分別命名 IDD_PAGE1、IDD_PAGE2、IDD_PAGE3。CPropertyPage,分別命名 CPage1、CPage2、CPage3。CListBox、CComboBox、int 等)。
// CMyPropSheet.h
class CMyPropSheet : public CPropertySheet {
DECLARE_DYNAMIC(CMyPropSheet)
public:
CPage1 m_page1;
CPage2 m_page2;
CPage3 m_page3;
CMyPropSheet(UINT nIDCaption, CWnd* pParent = NULL, UINT iSelectPage = 0);
CMyPropSheet(LPCTSTR pszCaption, CWnd* pParent = NULL, UINT iSelectPage = 0);
virtual ~CMyPropSheet();
};
// CMyPropSheet.cpp
CMyPropSheet::CMyPropSheet(LPCTSTR pszCaption, CWnd* pParent, UINT iSelectPage)
: CPropertySheet(pszCaption, pParent, iSelectPage) {
AddPage(&m_page1);
AddPage(&m_page2);
AddPage(&m_page3);
// 精靈模式:在 DoModal() 前呼叫
// SetWizardMode();
}
// 呼叫端 (如 View 類別)
CMyPropSheet sheet(_T("設定精靈"), this);
sheet.SetWizardMode(); // 關鍵:啟用精靈模式
if (sheet.DoModal() == ID_WIZFINISH) {
// 取得各頁資料...
}
在各 CPageN 覆寫 OnSetActive():
BOOL CPage1::OnSetActive() {
CPropertySheet* pSheet = (CPropertySheet*)GetParent();
pSheet->SetWizardButtons(PSWIZB_NEXT); // 首頁只有「下一步」
return CPropertyPage::OnSetActive();
}
BOOL CPage2::OnSetActive() {
CPropertySheet* pSheet = (CPropertySheet*)GetParent();
pSheet->SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT); // 中間頁
return CPropertyPage::OnSetActive();
}
BOOL CPage3::OnSetActive() {
CPropertySheet* pSheet = (CPropertySheet*)GetParent();
pSheet->SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH); // 尾頁「完成」
return CPropertyPage::OnSetActive();
}
覆寫 OnWizardNext() (按下「下一步」時) / OnWizardFinish() (按下「完成」時):**回傳 0 允許繼續,回傳 -1 取消跳轉**。
LRESULT CPage1::OnWizardNext() {
UpdateData(TRUE); // 從控制項讀取資料到變數
if (m_selectedJob < 0) { // 未選擇職業
AfxMessageBox(_T("請選擇職業"));
return -1; // 留在本頁
}
return 0; // 允許進入下一頁
}
LRESULT CPage3::OnWizardFinish() {
UpdateData(TRUE);
int idx = m_comboSalary.GetCurSel();
if (idx == CB_ERR) { AfxMessageBox(_T("請選擇薪資")); return -1; }
m_comboSalary.GetLBText(idx, m_strSalary);
return 0; // 允許結束精靈
}
在各頁 OnInitDialog() 中:
BOOL CPage1::OnInitDialog() {
CPropertyPage::OnInitDialog();
m_listBox.AddString(_T("項目一"));
m_listBox.AddString(_T("項目二"));
return TRUE;
}
void CMyView::OnShowWizard() {
CMyPropSheet sheet(_T("資料輸入精靈"), this);
sheet.SetWizardMode();
if (sheet.DoModal() == ID_WIZFINISH) {
m_strJob = sheet.m_page1.m_strJob;
m_strHobby = sheet.m_page2.m_strHobby;
m_strSalary = sheet.m_page3.m_strSalary;
Invalidate(); // 觸發 OnDraw 重繪
}
}
void CMyView::OnDraw(CDC* pDC) {
pDC->TextOut(10, 10, m_strJob);
pDC->TextOut(10, 30, m_strHobby);
pDC->TextOut(10, 50, m_strSalary);
}
SetWizardMode() 必須在 DoModal() 前呼叫。OnSetActive() 中透過 GetParent() 轉型為 CPropertySheet* 呼叫 SetWizardButtons()。OnWizardNext()/OnWizardFinish(),回傳 -1 阻擋跳轉。UpdateData(TRUE/FALSE)。