The big difference between a property sheet and a wizard
is that, before showing the dialog box, you must call the
SetWizardMode() member function of the CPropertySheet
class. Its syntax is:
void SetWizardMode();
As you can see, this member function takes no argument.
It simply informs the compiler that, instead of a property sheet, you want
to create a wizard. The real question is, where do you call this member
function? That's because you have various options. The secret is to call
before displaying the pages; that is, before calling
CDialog::DoModal(). You can call CPropertySheet::SetWizardMode() in
the same constructore where you add the pages, or you can call it just
before calling CDialog::DoModal().
Practical
Learning: Calling a Wizard
|
|
- In the Solution Explorer, double-click AutoRepair1.cpp and change it
as follows:
// AutoRepair1.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "AutoRepair1.h"
#include "CustomerInformationDlg.h"
#include "RepairOrderSheet.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CAutoRepair1App
BEGIN_MESSAGE_MAP(CAutoRepair1App, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
// CAutoRepair1App construction
CAutoRepair1App::CAutoRepair1App()
{
// support Restart Manager
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CAutoRepair1App object
CAutoRepair1App theApp;
// CAutoRepair1App initialization
BOOL CAutoRepair1App::InitInstance()
{
// InitCommonControlsEx() is required on Windows XP if an application
// manifest specifies use of ComCtl32.dll version 6 or later to enable
// visual styles. Otherwise, any window creation will fail.
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// Set this to include all the common control classes you want to use
// in your application.
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinApp::InitInstance();
AfxEnableControlContainer();
// Create the shell manager, in case the dialog contains
// any shell tree view or shell list view controls.
CShellManager *pShellManager = new CShellManager;
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need
// Change the registry key under which our settings are stored
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
// CCustomerInformationDlg dlg;
CRepairOrderSheet dlg(L"College Park Auto Repair");
m_pMainWnd = &dlg;
dlg.SetWizardMode();
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
// Delete the shell manager created above.
if (pShellManager != NULL)
{
delete pShellManager;
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
- To execute the project, press F5
- Notice that the Back button is enabled.
Click Next
- Click Next again
- Notice that there is no Finish button although you are on the last
page.
Close the dialog box and return to your programming environment
Configuring the Default Buttons of a Wizard
|
|
By default, after creating a regular wizard, it is
equipped with three buttons: Back, Next, and Cancel. If you select the
option to add help in the MFC Application, the wizard would also be equipped
with a Help button. You can manage the buttons and you have many options.
As with anything else in the world or programming, you
should make your wizard intuitive and friendly. For example, on the first
page, since there is no reason for the user to access the previous page, you
can disable the Back button. On the other hand, when the user gets to the
last page, since there is no succeeding page, there is no need for a Next
button. Consequently, you should replace it with a Finish button.
Fortunately, the display of these buttons is probably the easiest thing to
manage on a wizard.
In order to decide what button(s) should be available
when a particular page is accessed, generate its
CPropertyPage::OnSetActive() event. Its syntax is:
virtual BOOL OnSetActive( );
This event fires when a page of your choice is accessed,
allowing you to do what you want on the wizard page. One of the actions you
can take when a page displays is to decide what button(s) should be
displayed on the wizard. The buttons of a wizard are managed through the
CPropertySheet::SetWizardButtons() member function. Its
syntax is:
void SetWizardButtons(DWORD dwFlags);
The dwFlags argument is a constant or a
combination of values that defines the buttons to display. The possible
values are:
- PSWIZB_BACK for the Back button
- PSWIZB_NEXT for the Next button
- PSWIZB_FINISH for the Finish button
- PSWIZB_DISABLEDFINISH to disable the Finish button
On the first page, to display the Next button while
disabling the Back button, you can pass only the PSWIZB_NEXT
value. On the last page, you should display the Back and the Finish buttons.
All pages between the first and the last should display the Back and the
Next buttons, unless you have a reason to do otherwise.
Adding the Default Buttons of a Wizard
|
|
To add your own button to the wizard, you can use the
features of the CWnd class. Here is an example:
CmyWizardSheet::OnInitDialog()
{
BOOL bResult = CPropertySheet::OnInitDialog();
CButton *btnWhatever = new CButton;
btnWhatever->Create(L"Whatever", WS_CHILD | WS_VISIBLE,
CRect(10, 362, 126, 385), this, 0x122);
Return bResult;
}
When the user clicks the Back button, the
CPropertyPage::OnWizardBack() event fires, giving you the
opportunity to do what you judge necessary. Its syntax is:
virtual LRESULT OnWizardBack();
You should use this event on a page that has the Back
button and if this button is enabled. When the user clicks the Next button,
the CPropertyPage::OnWizardNext() event fires, allowing you
to take appropriate measures. Its syntax is:
virtual LRESULT OnWizardNext();
You should use this event on a page that has the Next
button. When the user clicks the Finish button, the
CPropertyPage::OnWizardFinish() event fires. Its syntax is:
virtual BOOL OnWizardFinish( );
This event should be implement when either the user is
on the last page that has the Finish button or at any time if the wizard has
a permanent Finish button available on all pages.
Practical
Learning: Implementing Wizard Buttons
|
|
- On the main menu, click Project -> Class Wizard...
- In the Class Name combo box, make sure that CCustomerInformationDlg
is selected (or select it).
Click the Virtual Funtions tab
- In the Virtual Functions list, double-click OnSetActive
- Click Edit Code
- Change the file as follows:
// CustomerInformationDlg.cpp : implementation file
//
#include "stdafx.h"
#include "AutoRepair1.h"
#include "CustomerInformationDlg.h"
#include "afxdialogex.h"
#include "RepairOrderSheet.h"
. . . No Change
BOOL CCustomerInformationDlg::OnSetActive()
{
// TODO: Add your specialized code here and/or call the base class
CRepairOrderSheet *ros = reinterpret_cast<CRepairOrderSheet *>(GetParent());
ros->SetWizardButtons(PSWIZB_NEXT);
return CPropertyPage::OnSetActive();
}
- Press F5 to execute
- Notice that the Back button is now disabled.
Close the dialog box
and return to your programming environment
- On the main menu, click Project -> Class Wizard...
- In the Class Name combo box, select CRepairSummaryDlg
- Click the Virtual Funtions tab
- In the Virtual Functions list, double-click OnSetActive
- In the Class Name combo box, select CJobsAndPartsDlg
- In the Virtual Functions list, double-click OnSetActive
- Click Edit Code
- Change the file as follows:
// JobsAndPartsDlg.cpp : implementation file
//
#include "stdafx.h"
#include "AutoRepair1.h"
#include "JobsAndPartsDlg.h"
#include "afxdialogex.h"
#include "RepairOrderSheet.h"
. . . No Change
BOOL CJobsAndPartsDlg::OnSetActive()
{
// TODO: Add your specialized code here and/or call the base class
CRepairOrderSheet *ros = reinterpret_cast<CRepairOrderSheet *>(GetParent());
ros->SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
return CPropertyPage::OnSetActive();
}
- Access the RepairSummaryDlg.cpp file
- Change the file as follows:
// RepairSummaryDlg.cpp : implementation file
//
#include "stdafx.h"
#include "AutoRepair1.h"
#include "RepairSummaryDlg.h"
#include "afxdialogex.h"
#include "RepairOrderSheet.h"
. . . No Change
BOOL CRepairSummaryDlg::OnSetActive()
{
// TODO: Add your specialized code here and/or call the base class
CRepairOrderSheet *ros = reinterpret_cast<CRepairOrderSheet *>(GetParent());
ros->SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH);
return CPropertyPage::OnSetActive();
}
- To test the application, press F9
- Close the dialog box and return to your programming environment
- Access the RepairSummaryDlg.cpp file and delete |
PSWIZB_FINISH from the code you wrote:
OOL CRepairSummaryDlg::OnSetActive()
{
// TODO: Add your specialized code here and/or call the base class
CRepairOrderSheet *ros = reinterpret_cast<CRepairOrderSheet *>(GetParent());
ros->SetWizardButtons(PSWIZB_BACK);
return CPropertyPage::OnSetActive();
}
- On the main menu, click Project -> Class Wizard...
- In the Class Name combo box, select CRepairOderSheet and click the
Virtual Functions tab
- In the Virtual Functions list, double-click OnInitDialog
- Click Edit Code
- Change the file as follows:
BOOL CRepairOrderSheet::OnInitDialog()
{
BOOL bResult = CPropertySheet::OnInitDialog();
// TODO: Add your specialized code here
CButton *btnFinish;
btnFinish = reinterpret_cast<CButton *>(GetDlgItem(IDCANCEL));
btnFinish->SetWindowText(L"Finish");
CButton *btnClose;
btnClose = reinterpret_cast<CButton *>(GetDlgItem(IDHELP));
btnClose->SetWindowText(L"Close");
return bResult;
}
- On the main menu, click Project -> Class Wizard...
- In the Class Name combo box, make sure CRepairOrderSheet is selected
and click the Commands tab.
In the Object IDs list, double-click
IDCANCEL
- Change the Member Function Name to OnFinishRepairOrder
- Click OK
- In the Object IDs list, double-click IDHELP
- Change the Member Function Name to OnCloseRepairOrder
- Click OK
- Click Edit Code
- Implement the events as follows:
void CRepairOrderSheet::OnFinishRepairOrder()
{
// TODO: Add your command handler code here
AfxMessageBox(L"The Finish button of the wizard was clicked.");
}
void CRepairOrderSheet::OnCloseRepairOrder()
{
// TODO: Add your command handler code here
AfxMessageBox(L"The repair order will be closed!");
PostQuitMessage(0);
}
- To execute, press F9
- Close the dialog box and return to your programming environment
|
|