Home

Wizards

 
 

Introduction to Wizard Pages

A wizard, like a property sheet, is a series of dialog boxes that are considered as one entity, tremendously saving the available space. When put together, the dialog boxes are referred to as wizard pages. Like the property pages, the wizard pages can help the programmer add more Windows controls than a single dialog box with the same dimension would allocate. While the property pages are positioned one in front of the others in a z-axis, the wizard pages are positioned so that, when one displays, the others are completely hidden. While a property page can be accessed by the user clicking its tab to bring it to the front and send the others to the back, a wizard is equipped with buttons such as Back or Next.

Creating Wizard Pages

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.

  1. As an example, start a new Dialog-Based project named Employment and create it as  with no About Box

  2. On the dialog, delete the TODO line, the OK, and the Cancel buttons

  3. While the dialog box is displaying, access its properties.

  4. Change its Caption to Personal Information

  5. Change its Style value to Child

  6. Change its Border to Thin

  7. Remove the check mark of the System Menu check box or set it to False

  8. 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

  9. Save All

  10. From the Controls toolbox, click the Edit Box button and click anywhere in the dialog box

  11. Open the header file of the dialog
    Change its base class to CPropertyPage
     
    class CEmploymentDlg : public CPropertyPage
    {
    // Construction
    public:
    . . .

  12. 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;
    }
  13. Save All

  14. On the main menu, click either Insert -> Resource… (MSVC 6) or Project -> Add Resource… (MSVC 7)

  15. In the Add Resource dialog box, click the + button of Dialog to expand it

  16. Click IDD_PROPPAGE_LARGE
     

  17. Click New

  18. Delete the TODO line

  19. Change the ID of the new dialog to IDD_EXPERIENCE and its Caption to Experience

  20. On the Controls toolbox, click the Slider button and click anywhere on the dialog box

  21. 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

  22. Add another IDD_PROPPAGE_LARGE property page. Delete its TODO line. Change its ID to IDD_EDUCATION and its Caption to Education

  23. On the Controls toolbox, click the Check Box button and click anywhere on the dialog

  24. Create or Add A New Class for the IDD_EDUCATION dialog box
    Name it CEducation
    Base it on the CPropertyPage class

  25. Save All

Wizard Configuration

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();

  1. Add a new class named of the class to CEmplSheet

  2. In the Base Class combo box, select CPropertySheet

  3. Click OK or Finish

  4. 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;
    }
    
  5. Test the application
     

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

Related Articles:

Button
 

Copyright © 2003-2007 FunctionX, Inc.