Home

Property Pages

 

Introduction

A property page is a dialog box, that can be positioned in front of, or behind of, another. This has the advantage of providing various dialog boxes that are “physically” grouped as one entity. Each part is represented by a tab. The tabs are usually positioned in the top section and each is used to identify a particular page:

 

To use a property page, the user clicks one. The page clicked becomes positioned in front of the other(s). The user can click another tab to select a different page:

Creating Property Pages

A property 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 property 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 Practical Learning: Creating Property Pages

 
  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 ID to IDD_EMPLOYMENT_DLG

  5. Change its Caption to Personal Information

  6. Change its Style value to Child

  7. Change its Border to Thin

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

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

  10. Save All

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

  12. Open the header file of the dialog
    Change its base class to CPropertyPage
     
    class CEmploymentDlg : public CPropertyPage
    {
    // Construction
    public:
    	CEmploymentDlg(CWnd* pParent = NULL);	// standard constructor
    
    // Dialog Data
    	//{{AFX_DATA(CEmploymentDlg)
    	enum { IDD = IDD_EMPLOYMENT_DLG };
    		// NOTE: the ClassWizard will add data members here
    	//}}AFX_DATA
    
    	// ClassWizard generated virtual function overrides
    	//{{AFX_VIRTUAL(CEmploymentDlg)
    	protected:
    	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support
    	//}}AFX_VIRTUAL
    
    // Implementation
    protected:
    	HICON m_hIcon;
    
    	// Generated message map functions
    	//{{AFX_MSG(CEmploymentDlg)
    	virtual BOOL OnInitDialog();
    	afx_msg void OnPaint();
    	afx_msg HCURSOR OnQueryDragIcon();
    	//}}AFX_MSG
    	DECLARE_MESSAGE_MAP()
    };

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

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

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

  17. Click IDD_PROPPAGE_LARGE
     

  18. Click New

  19. Delete the TODO line

  20. Change the ID of the new dialog to IDD_EXPERIENCE_DLG and its Caption to Experience

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

  22. 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 CExperienceDlg 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 CExperienceDlg and, in the Base Class combo box, select CPropertyPage
    Click Finish

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

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

  25. Create or Add A New Class for the IDD_EDUCATION_DLG dialog box
    Name it CEducationDlg
    Base it on the CPropertyPage class

  26. Save All

Property Sheets

To implement its functionality, the property pages are put together and kept as an entity by an object called a property sheet that 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 a 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 property 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. It 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.

 

Practical Learning Practical Learning: Creating Property Sheets

 
  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 "ExperienceDlg.h"
    #include "EducationDlg.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;
    	CExperienceDlg Exp;
    	CEducationDlg  Educ;
    
    	EmpSheet.AddPage(&Empl);
    	EmpSheet.AddPage(&Exp);
    	EmpSheet.AddPage(&Educ);
    
    	m_pMainWnd = &EmpSheet;
    
    	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)

Download

Related Articles:

Button
 

Copyright © 2003-2005 FunctionX, Inc.