|
A wizard page is designed from a dialog box and it must
have the following characteristics:
-
Style: Child or WS_CHILD
-
Border: Thin or WS_POPUP
-
Title Bar: True or WS_CAPTION
-
System Menu: False or no WS_SYSMENU
-
Visible: False or no WS_VISIBLE
-
Disabled: True or WS_DISABLED
You can create each page like that and with the same size. If you create dialog boxes that have different sizes, the dimensions of the taller and/or wider will be applied to all the other property pages when they come up.
Visual C++ makes it easy to create resources for property pages by displaying the Add Resource dialog box, expanding the Dialog node and selecting one of the IDD_PROPPAGE_X items.
After adding the resource for the property page, as done for a dialog box, you can add a class for it. Unlike the regular dialog box, a property page is based on the CPropertyPage class which itself is based on CDialog. The CPropertyPage class is declared in the afxdlgs.h header file.
|
Practical Learning: Introducing Wizard Pages
|
|
-
As an example, start a new Dialog-Based project named
Employment and create it as with no About Box
-
On the dialog, delete the TODO line, the OK, and the Cancel buttons
-
While the dialog box is displaying, access its properties.
-
Change its Caption to Personal Information
-
Change its Style value to Child
-
Change its Border to Thin
-
Remove the check mark of the System Menu check box or set it to False
-
Set its Visible property to False or remove its check mark
If necessary, remove the check mark of the Disabled check box or set it to False
-
Save All
-
From the Controls toolbox, click the Edit Box button and click anywhere in the dialog box
-
Open the header file of the dialog
Change its base class to CPropertyPage
class CEmploymentDlg : public CPropertyPage
{
// Construction
public:
. . .
|
- Change the source file of the EmploymentDlg.cpp class as follows:
// EmploymentDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Employment.h"
#include "EmploymentDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CEmploymentDlg dialog
CEmploymentDlg::CEmploymentDlg(CWnd* pParent /*=NULL*/)
: CPropertyPage(CEmploymentDlg::IDD)
{
//{{AFX_DATA_INIT(CEmploymentDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CEmploymentDlg::DoDataExchange(CDataExchange* pDX)
{
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CEmploymentDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CEmploymentDlg, CPropertyPage)
//{{AFX_MSG_MAP(CEmploymentDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CEmploymentDlg message handlers
BOOL CEmploymentDlg::OnInitDialog()
{
CPropertyPage::OnInitDialog();
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CEmploymentDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CPropertyPage::OnPaint();
}
}
HCURSOR CEmploymentDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
|
-
Save All
-
On the main menu, click either Insert -> Resource… (MSVC 6) or Project -> Add Resource…
(MSVC 7)
-
In the Add Resource dialog box, click the + button of Dialog to expand it
-
Click IDD_PROPPAGE_LARGE

-
Click New
-
Delete the TODO line
-
Change the ID of the new dialog to IDD_EXPERIENCE and its Caption to
Experience
-
On the Controls toolbox, click the Slider button
and click anywhere on the dialog box
-
If you are using MSVC 6, right-click the Experience dialog box and click
ClassWizard. A message box will display. Read it. Select Create A New Class and click OK.
Type CExperience and, in the Base Class combo box, select CPropertyPage
Click OK twice
If you are using MSVC 7, right-click the dialog box and click Add Class…
Type the Class Name as CExperience and, in the Base Class combo box, select CPropertyPage
Click Finish
-
Add another IDD_PROPPAGE_LARGE property page. Delete its TODO line. Change its ID to
IDD_EDUCATION and its Caption to Education
-
On the Controls toolbox, click the Check Box button
and click anywhere on the dialog
-
Create or Add A New Class for the IDD_EDUCATION dialog box
Name it CEducation
Base it on the CPropertyPage class
-
Save All
To implement its functionality, the wizard pages are put together and kept as an entity by an object called a property sheet. The property sheet acts as their parent. Like other controls, we will see that the property pages must be added to a property sheet.
There is no resource to create for a property sheet. A property sheet is based on the
CPropertySheet class, which is not based on CDialog but it provides the same functionality as dialog. Therefore, a property sheet is sometimes called, or referred to as, a dialog box. Instead,
CPropertySheet is based on the CWnd class. Therefore, to implement your
wizard page(s), you can simply declare a CPropertySheet variable and use it to display the application or you can programmatically derive a class from
CPropertySheet. The CPropertySheet class is declared in the afxdlgs.h header file.
If you decide to directly use the CPropertySheet class, declare a variable for it where the application will need to be displayed or instantiated, which could be in the
CWinApp::InitInstance() event. To display the property sheet, call its DoModal() method. This could be done as follows:
BOOL CMyApp::InitInstance()
{
CPropertySheet MySheet;
MySheet.DoModal();
}
To specify your property pages as belonging to the property page, declare a variable for each one of them. Then, call the
CPropertySheet::AddPage() method to add each property page. The syntax of this method is:
void AddPage(CPropertyPage *pPage);
This method takes the variable of each page and adds it as part of the property sheet. Here is an example:
BOOL CmyApp::InitInstance()
{
CPropertySheet MySheet;
CFirstPage First;
CSecondPage Second;
MySheet.AddPage(&First);
MySheet.AddPage(&Second);
MySheet.DoModal();
}
If you want to have better access to the property sheet as a class, you should derive your own class from CPropertySheet. You will have the ability to use any or a combination of these constructors:
CPropertySheet();
CPropertySheet(UINT nIDCaption, CWnd *pParentWnd=NULL, UINT iSelectPage=0);
CPropertySheet(LPCTSTR pszCaption, CWnd *pParentWnd=NULL, UINT iSelectPage=0);
The default constructor is used in the same circumstance as the CPropertySheet variable declared above. Its allows you to create a CPropertySheet instance and change its characteristics later. Both the second and the third constructors allow you to specify a caption for the property. If you want to use the first, create a string with an identifier in a String Table and use that ID as the argument. Otherwise, when declaring a variable using the second constructor, you can directly provide a null-terminated string as argument.
If you want to specify a title for the property sheet, you can call the CPropertySheet::SetTitle() method. Its syntax is:
void SetTitle(LPCTSTR lpszText, UINT nStyle = 0);
The first argument is a null terminated string that will be the new title. If you want the caption to display the string starting with “Properties for”, pass a second argument as
PSH_PROPTITLE.
Each page is based on the CPropertyPage class. To display the wizard, use the CPropertySheet class in the exact same way as seen for the property pages above. The only difference is that, to make this a wizard, you must call the
CPropertySheet::SetWizardMode() method before calling DoModal(). The syntax of the
SetWizardMode() member function is:
Void SetWizardMode();
|
Practical Learning: Implementing Wizard Pages
|
|
-
Add a new class named of the class to CEmplSheet
-
In the Base Class combo box, select CPropertySheet
-
Click OK or Finish
-
Change the source code of the CEmploymentApp class as follows:
// Employment.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "Employment.h"
#include "EmploymentDlg.h"
#include "EmplSheet.h"
#include "Experience.h"
#include "Education.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CEmploymentApp
BEGIN_MESSAGE_MAP(CEmploymentApp, CWinApp)
//{{AFX_MSG_MAP(CEmploymentApp)
//}}AFX_MSG
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CEmploymentApp construction
CEmploymentApp::CEmploymentApp()
{
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CEmploymentApp object
CEmploymentApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CEmploymentApp initialization
BOOL CEmploymentApp::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
CEmplSheet EmpSheet("Employment Application");
CEmploymentDlg Empl;
CExperience Exp;
CEducation Educ;
EmpSheet.AddPage(&Empl);
EmpSheet.AddPage(&Exp);
EmpSheet.AddPage(&Educ);
m_pMainWnd = &EmpSheet;
EmpSheet.SetWizardMode();
int nResponse = EmpSheet.DoModal();
if (nResponse == IDOK)
{
}
else if (nResponse == IDCANCEL)
{
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
|
-
Test the application

-
Return to MSVC and close the project (MSVC 6: File -> Close Workspace; MSVC 7: File -> Close Solution)
|
|