创建一个更好的属性表类
在OnOptions()中创建属性表是个好主意,但是在这里使用很多初始化代码却非常糟糕,这不是CMainFrame应该做得事情。更好的方法是从CPropertySheetImpl派生一个新类,在这个类中完成这些任务。
#include "BackgroundOptsPage.h"
class CAppPropertySheet : public CPropertySheetImpl<CAppPropertySheet> { public: // Construction CAppPropertySheet ( _U_STRINGorID title = (LPCTSTR) NULL, UINT uStartPage = 0, HWND hWndParent = NULL );
// Maps BEGIN_MSG_MAP(CAppPropertySheet) CHAIN_MSG_MAP(CPropertySheetImpl<CAppPropertySheet>) END_MSG_MAP()
// Property pages 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 ); } |
这样一来,OnOptions()处理函数就变得简单了一些:
void CMainFrame::OnOptions ( UINT uCode, int nID, HWND hwndCtrl ) { CAppPropertySheet sheet ( _T("PSheets Options"), 0 );
sheet.m_pgBackground.m_nColor = m_view.m_nColor; sheet.m_pgBackground.m_nPicture = m_view.m_nPicture;
if ( IDOK == sheet.DoModal() ) m_view.SetBackgroundOptions ( sheet.m_pgBackground.m_nColor,sheet.m_pgBackground.m_nPicture ); } |
创建一个向导样式的属性表
创建一个向导和创建一个属性表很相似,这并不奇怪,只需稍做修改添加“上一步”和“下一步”按钮就行了。和MFC一样,你需要重载OnSetActive()函数并调用SetWizardButtons()使相应的按钮可用。我们先从一个简单的介绍页面开始,它的ID是IDD_WIZARD_INTRO:

注意这个页面没有标题栏文字,因为向导中的所有的页面通常都有相同的标题,我更愿意在CPropertySheetImpl的构造函数中设置这些文字,然后每个页面使用这个字符串资源。这就是为什么我只需要改变一个字符串就能改变所有页面标题文字的原因。
关于这个页面的实现代码在CWizIntroPage类中:
class CWizIntroPage : public CPropertyPageImpl<CWizIntroPage> { public: enum { IDD = IDD_WIZARD_INTRO };
// Construction CWizIntroPage();
// Maps BEGIN_MSG_MAP(COptionsWizard) CHAIN_MSG_MAP(CPropertyPageImpl<CWizIntroPage>) END_MSG_MAP()
// Notification handlers int OnSetActive(); }; |
构造函数使用(引用)一个字符串资源ID来设置页面的文字:
CWizIntroPage::CWizIntroPage() : CPropertyPageImpl<CWizIntroPage>( IDS_WIZARD_TITLE ) {} |
当这个页面激活时,字符串IDS_WIZARD_TITLE ("PSheets Options Wizard")将出现在向导的标题栏。OnSetActive()仅仅使“下一步”按钮可用:
int CWizIntroPage::OnSetActive() { SetWizardButtons ( PSWIZB_NEXT ); return 0; } |
为了实现一个向导,我们需要创建一个类COptionsWizard,还要在主窗口添加菜单Tools|Wizard。COptionsWizard类的构造函数和CAppPropertySheet类的构造函数一样,只是设置必要的样式标志和添加页面。
class COptionsWizard : public CPropertySheetImpl<COptionsWizard> { public: // Construction COptionsWizard ( HWND hWndParent = NULL );
// Maps BEGIN_MSG_MAP(COptionsWizard) CHAIN_MSG_MAP(CPropertySheetImpl<COptionsWizard>) END_MSG_MAP()
// Property pages CWizIntroPage m_pgIntro; };
COptionsWizard::COptionsWizard ( HWND hWndParent ) : CPropertySheetImpl<COptionsWizard> ( 0U, 0, hWndParent ) { SetWizardMode();
AddPage ( m_pgIntro ); } |
CMainFrame类的Tools|Wizard菜单处理函数是这个样子:
void CMainFrame::OnOptionsWizard ( UINT uCode, int nID, HWND hwndCtrl ) { COptionsWizard wizard; wizard.DoModal(); } |
这就是向导的效果:
|