A Vc++ Mfc Example - PropertyPage and PropertySheet

Updated on August 27, 2018
sirama profile image

I am a software engineer. I have been working with C++, MFC, and .net technologies for 15 years. I like video games and reading books.

1. Introduction

Property Pages are widely used to accommodate multiple controls in different pages. Each Property Sheet defines a group of controls that together forms logically related information. In this article, we will see how we can create a property page using MFC. With a little change, you can deform the property pages as wizard pages.

2. About the Sample

The Example is a MFC Dialog Based Application, which launches the property page dialog. Below is the screenshot of hosting dialog:

Main Dialog which launches PropertySheet Dialog
Main Dialog which launches PropertySheet Dialog | Source

The below screen shot is the property page:

MFC PropertyPage Dialog
MFC PropertyPage Dialog | Source

Note the sample has two pages in the Property Page Dialog. When you click "Settings…" button in the main dialog, the property page dialog will be opened. Once you change any of the default value from the displayed dialog, the apply button will be enabled. Clicking the apply button will make your change permanent not considering whether you cancel the dialog or click ok. You can also save the changes by clicking the OK button as well.

Then what is the use of apply button? In real world if you want to show the changes visually, the button is very useful and the user of the application will look at the visual changes and tune their settings further.

3. How do we Create Property Page Dialog?

The below skeleton diagram explains how to create the property page dialog.

Creating Property Page Dialog
Creating Property Page Dialog | Source

First, we should create property pages. Then we should attach these property pages to the Property Sheet, which provides the buttons required for Property Page dialog. OK and Cancel buttons are common for a dialog. The Apply button is provided especially for Property Page Dialogs by the Property Sheet. Creating the Property Pages is almost equal to creating the dialog boxes. In the resource editor, you can ask for property page and you will get a border-less dialog. On this dialog, drop the controls you want for your property page.

In the above skeleton picture, first, we will create property page1 and page2 using Dialog Template Editor. Then the required controls are dropped into page1 and page2. Finally, through the code, we will add these pages to the Property Sheet which gets created at runtime.

4. Creating Property Pages

How do you create a dialog? Property page also created similar to that. Creating the first page of the property dialog is shown in the below video link:

Video 1: Creating First Property Page (No Audio)

Steps

  1. From the Resource file add the Property Page
  2. Then provide a meaningful ID Name for it
  3. Open the Property page in visual studio editor
  4. From the Toolbox add three radio buttons.

So that’s all we do for creating the pages. Repeat the same process as shown in the video for all other pages. Once the pages are ready, we should create associated class for it. The video below shows how to create a class for the Property page added in the previous video:

Video 2: Adding a Class for Property Page (No Audio)

Steps

  1. The Property page template is opened in visual studio
  2. Add Class menu option is invoked from the context menu of the Property page template (By Right click)
  3. In the class dialog, a class name is chosen, and base class is set to CPropertyPage
  4. Created class is shown in the class view

We create the Second page of the example by following the same procedure as shown in previous two videos. Now, we have Property Page1 and Property Page2 for the property dialog is ready. The design of the second property page is below:

Design of Second Property Page
Design of Second Property Page | Source

5. Add Control Variables

Now the Color and Font property page templates are ready. Now we will associate a variable to the controls in these property page templates. First, a variable is associated with the radio buttons. For all the three radio buttons, only one variable is associated and we treat these radio buttons as a single group. First, we should make sure that the Tab Order for all the radio buttons goes consecutively. Then for the first radio button in the tab order, set the group property to true.

One can invoke the Tab Order using Format=>Tab Order menu item or by simply pressing the Ctrl + d from the keyboard.

The below-specified video shows adding a control variable for the Radio buttons:

Video 3: Adding Control Variable to Radio Group (No Audio)

Steps

  1. From the resource view, Property page for the font is opened
  2. Make sure Group property is set to true. If not set it to true
  3. Add variable dialog is opened for first radio button
  4. Variable category is changed from control to variable
  5. A variable of type BOOL is added (Later we will change this as int through the code)

Likewise, we add three more value type variables for each text box control in the second Property Page. The below screen shot shows an int value variable m_edit_val_Red added for the first edit box. The variable association for blue and green can also be done in the same way.

Second Property Page Variable Association
Second Property Page Variable Association | Source

6. OnApply Message Map for Property pages

ON_MESSAGE_VOID is a nice handler for dealing with custom messages that do not require passing any arguments. In our Example, we will use this handler for dealing with WM_APPLY user-defined message. Below is the code change which is required for the dialog-based project.

1) First, a required header is included in the dialog class header file

//Sample 01: Include the header required for OnMessageVoid
#include <afxpriv.h>

2) In the same header file add declaration for the "void message" handler function.

//Sample 02: Declare the Message Handler function
afx_msg void OnApply();

3) Next in the CPP file, ON_MESSAGE_VOID Macro is added in between Begin Message Map and End Message Map. The OnApply Function is not yet defined, so we will get a compiler error when we compile the program at present. We can avoid this by providing a dummy implementation for OnApply like void CPropPageSampleDlg::OnApply() {}

//Sample 03: Provide Message map 
//entry for the Apply button click
ON_MESSAGE_VOID(WM_APPLY, OnApply)

4) We have not handled the WM_APPLY till now and note that it is not an MFC pre-defined message. To support this, we will declare a user-defined massage in the "stdAfx.h" header file. WM_USER macro is useful to define a user-defined message safely. That is; the WM_APPLY does not clash with any existing user-defined message as we use it cautiously like WM_USER+1

//Sample 04: Define the user defined message
#define WM_APPLY WM_USER + 1

7. Change Radio Button Variable

In video 3, we added a Boolean type variable for the radio buttons group. It will be useful if we change this variable type from BOOL to an integer type. When a user makes a radio button selection, the data exchange mechanism will set the variable to denote the selected radio button. We will get more clarity when we write the code for the radio check state later. For now, we will just change Boolean variable type to an integer.

1) In the PropPageFont.h file, the variable type is changed from Boolean to Integer

//Sample 05: Change the variable type to Int
int m_ctrl_val_radio_font;

2) Next, in the constructor of the CPropPageFont, we initialize the variable to –1. This value denotes that none of the radio buttons are checked.

//Sample 06: Set the Combo value variable to -1
CPropPageFont::CPropPageFont()
	: CPropertyPage(CPropPageFont::IDD)
	, m_ctrl_val_radio_font(-1)
{

}

8. CPropPageSampleDlg Dialog class

We know that Application Wizard created the class CPropPageSampleDlg. Moreover, we will launch the Property Page Dialog from this dialog as a child dialog. The CPropPageSampleDlg will take the settings from the Property Pages and captures that internally. When we open the Property Page for next time, it supplies the settings cached by this parent dialog back to the Property Pages.

1) First, I declare the variables required for caching the settings in the class declaration, which is in the header file

//Sample 07: Add Member variables to keep track of settings
private:
	int m_selected_font;
	int m_blue_val;
	int m_red_val;
	int m_green_val;

2) Next in the OnInitDialog, these variables are initialized with the default values. When we invoke the Property Page for the first time, the page shows these default values to the user.

//Sample 08: Initialize the member variables
m_selected_font = -1;
m_red_val = 0;
m_green_val = 0;
m_blue_val = 0;

9. Create Property Dialog and Display it

From the dialog class, the Property Page dialog is created and displayed as a Modal Dialog. Once this Property Page Dialog is closed by the user, the settings set by him/her is read back and cached inside the parent dialog.

9.1 Create Property Sheet

In the button click handler, first, we create a CPropertySheet instance with a dialog title Settings. The second parameter passed is referred by the property sheet as its parent.

//Sample 09: Create Property Pages, 
//Attach it to the sheet and Lauch it
void CPropPageSampleDlg::OnBnClickedButtonSettings()
{
	//Sample 9.1: Create Property Sheet
	CPropertySheet sheet(_T("Settings") , this);

9.2 Declaring CPropertyPages

Next, we declare the property pages to store it in the heap later. First, we add required header file of the dialog class, then we declare the required variables in the class with a private scope. Code is below

//Sample 9.2: Include Property pages
#include "PropPageFont.h"
#include "PropPageColor.h"

//Add below the  int m_green_val;
CPropPageFont* m_page1_font;
CPropPageColor* m_page2_color;

9.3 Creating Property Pages and Adding it to Property Sheet

1) In the implementation file (Look at section 9.1), after creating the property sheet with title settings, we create both the property pages (i.e.) Font and Color pages.

//Sample 9.3: Create Property Pages
m_page1_font = new CPropPageFont();
m_page2_color = new CPropPageColor();

2) Once the pages are available, we set the dialog-cached values to the controls on the property pages

//Sample 9.4: Pass the previous settings to property pages
m_page1_font->m_ctrl_val_radio_font = m_selected_font ;
m_page2_color->m_edit_val_Red = m_red_val;
m_page2_color->m_edit_val_Green = m_green_val;
m_page2_color->m_edit_val_Blue = m_blue_val; 

3) Then the property pages are attached to the property sheet. Once this step is complete, the property dialog is ready with two pages. The title of each tab is taken from its caption property that you set when you designed the Property Page.

//Sample 9.5: Add Property Pages to Property Sheet
sheet.AddPage(m_page1_font);
sheet.AddPage(m_page2_color);

9.4 Display Property Sheet

When the property dialog is closed, we check the return value and make a call to the OnApply() function. In that function we will implement the code which will copy the settings from Property Pages. After the OnApply call, we clear the Property Pages from the Heap.

//Sample 9.6: Display the property sheet 
//and call on_apply when the sheet is closed
if (sheet.DoModal() == IDOK)
	OnApply();
delete m_page1_font;
delete m_page2_color;

10. Set Modified Flag to Enable Apply Button

The "apply" Button in the Property dialog is enabled when the UI elements in the pages are changed. Say, for example, typing the new red value in the text box will enable the apply Button. Once we click the apply Button, the changes are informed to its parent. In our case, we send the data entered or changed by the user so for, to the parent dialog that launched this Property Page. In real world, the apply Button will immediately apply the settings to the application. So before clicking OK, the user can observe the effect of the changed settings just by clicking the apply Button.

With all that said, we need to track the changes done in the Property dialog. For that, we will handle the BN_CLICKED event for the Radio Buttons in the Font Property Page and EN_CHANGE event for the text boxes in the Color Property Page. The event BN_CLICKED will appear when somebody clicked the Radio Button and the event EN_CHANGE will appear when the content of the text is changed.

How we add a handler for Radio Button is shown in the below video:

Video 4: Add Handlers for Radio Button Click [No Audio]

Steps

  1. FONT property page is opened
  2. First, Radio button in the group is clicked
  3. In the properties pane, navigation moved to control events
  4. BN_CLICKED event is double clicked (Visual Studio Takes us code editor)
  5. The process is repeated for other two radio buttons.

The same way, we provide the handlers for the EN_CHANGED event for all the three text boxes. The below screen shot shows how the request for the event handler for the control event EN_CHANGED is done:

EN_CHANGE Handler For Text Boxes
EN_CHANGE Handler For Text Boxes | Source

1) In the handler provided by the Radio buttons, we set the flag to enable the "apply" button by calling the function SetModified.

// CPropPageFont message handlers
//Sample 10: Call Set Modified to Enable Apply Button.
void CPropPageFont::OnBnClickedRadio1()
{
	SetModified();
}

void CPropPageFont::OnBnClickedRadio2()
{
	SetModified();
}

void CPropPageFont::OnBnClickedRadio3()
{
	SetModified();
}

2) The same way we set the modified flag for the text boxes also. Below is the handler code:

// CPropPageColor message handlers
//Sample 12: Call Set Modified to Enable Apply Button.
void CPropPageColor::OnEnChangeEdit1()
{
	SetModified();
}

void CPropPageColor::OnEnChangeEdit2()
{
	SetModified();
}

void CPropPageColor::OnEnChangeEdit3()
{
	SetModified();
}

11. Sending WM_APPLY through OnApply Override of PropertyPage

We had a dummy handler for the user-defined message WM_APPLY (Refer Section 6 of this article) and now; we implement that. The property page will send the notification to this dialog when the user clicks the apply button of the property page. Have a look at the implementation below:

//Sample 13: Provide handler for Applying 
//the property sheet changes
void CPropPageSampleDlg::OnApply() 
{
	m_selected_font = 
		m_page1_font->m_ctrl_val_radio_font;
	m_red_val = 
		m_page2_color->m_edit_val_Red;
	m_green_val = 
		m_page2_color->m_edit_val_Green;
	m_blue_val = 
		m_page2_color->m_edit_val_Blue;
}

The parent dialog will take the data from both the property pages and stores that internally. Also, note that the property pages are wiped out from the memory after use and new instances of property pages are created when we display it. Now refer the code at section 9.4, you will get an idea of how the data flow of the settings will happen.

  1. When the Parent about to display the property page, it copies the cached data to the property pages.
  2. When the user clicks the OK button, this OnApply is called (Refer section 9.6)
  3. When the user clicks the Apply button, WM_APPLY user message is sent to the CPropPageSampleDlg.

The below code will send the WM_APPLY message to the parent dialog:

//Sample 14: Set the Modified flag to false, 
//and send message to dialog class
BOOL CPropPageFont::OnApply()
{
	CPropertySheet* pSheet = 
		(CPropertySheet*) GetParent();  
	pSheet->GetParent()->SendMessage(WM_APPLY);
	SetModified(FALSE);
	return CPropertyPage::OnApply();
}

Note that the OnApply is overridden in the Property Page class for Fonts. Moreover, the OnApply overridden function (For all the Property page that overrode OnApply) is called by the MFC Frame work when the user clicks the apply button. As we are just going to send the message to the parent dialog of the property page when Apply button is clicked by the user, providing the overridden version of the function in either Font or Color page is sufficient. The below video shows adding the OnApply override:

Video 5: Overriding OnApply Function (No Audio)

Steps

  1. Property page for CPropPageFont is opened
  2. In the Property Page, Overrides toolbar icon is selected
  3. Then, OnApply Override is added to the source code.

The below video shows completed Example in Action:

Video 6: Completed Example in Action [No Audio]

Source Code: Download

Questions & Answers

    © 2018 sirama

    Comments

      0 of 8192 characters used
      Post Comment

      No comments yet.

      working

      This website uses cookies

      As a user in the EEA, your approval is needed on a few things. To provide a better website experience, owlcation.com uses cookies (and other similar technologies) and may collect, process, and share personal data. Please choose which areas of our service you consent to our doing so.

      For more information on managing or withdrawing consents and how we handle data, visit our Privacy Policy at: https://owlcation.com/privacy-policy#gdpr

      Show Details
      Necessary
      HubPages Device IDThis is used to identify particular browsers or devices when the access the service, and is used for security reasons.
      LoginThis is necessary to sign in to the HubPages Service.
      Google RecaptchaThis is used to prevent bots and spam. (Privacy Policy)
      AkismetThis is used to detect comment spam. (Privacy Policy)
      HubPages Google AnalyticsThis is used to provide data on traffic to our website, all personally identifyable data is anonymized. (Privacy Policy)
      HubPages Traffic PixelThis is used to collect data on traffic to articles and other pages on our site. Unless you are signed in to a HubPages account, all personally identifiable information is anonymized.
      Amazon Web ServicesThis is a cloud services platform that we used to host our service. (Privacy Policy)
      CloudflareThis is a cloud CDN service that we use to efficiently deliver files required for our service to operate such as javascript, cascading style sheets, images, and videos. (Privacy Policy)
      Google Hosted LibrariesJavascript software libraries such as jQuery are loaded at endpoints on the googleapis.com or gstatic.com domains, for performance and efficiency reasons. (Privacy Policy)
      Features
      Google Custom SearchThis is feature allows you to search the site. (Privacy Policy)
      Google MapsSome articles have Google Maps embedded in them. (Privacy Policy)
      Google ChartsThis is used to display charts and graphs on articles and the author center. (Privacy Policy)
      Google AdSense Host APIThis service allows you to sign up for or associate a Google AdSense account with HubPages, so that you can earn money from ads on your articles. No data is shared unless you engage with this feature. (Privacy Policy)
      Google YouTubeSome articles have YouTube videos embedded in them. (Privacy Policy)
      VimeoSome articles have Vimeo videos embedded in them. (Privacy Policy)
      PaypalThis is used for a registered author who enrolls in the HubPages Earnings program and requests to be paid via PayPal. No data is shared with Paypal unless you engage with this feature. (Privacy Policy)
      Facebook LoginYou can use this to streamline signing up for, or signing in to your Hubpages account. No data is shared with Facebook unless you engage with this feature. (Privacy Policy)
      MavenThis supports the Maven widget and search functionality. (Privacy Policy)
      Marketing
      Google AdSenseThis is an ad network. (Privacy Policy)
      Google DoubleClickGoogle provides ad serving technology and runs an ad network. (Privacy Policy)
      Index ExchangeThis is an ad network. (Privacy Policy)
      SovrnThis is an ad network. (Privacy Policy)
      Facebook AdsThis is an ad network. (Privacy Policy)
      Amazon Unified Ad MarketplaceThis is an ad network. (Privacy Policy)
      AppNexusThis is an ad network. (Privacy Policy)
      OpenxThis is an ad network. (Privacy Policy)
      Rubicon ProjectThis is an ad network. (Privacy Policy)
      TripleLiftThis is an ad network. (Privacy Policy)
      Say MediaWe partner with Say Media to deliver ad campaigns on our sites. (Privacy Policy)
      Remarketing PixelsWe may use remarketing pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to advertise the HubPages Service to people that have visited our sites.
      Conversion Tracking PixelsWe may use conversion tracking pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to identify when an advertisement has successfully resulted in the desired action, such as signing up for the HubPages Service or publishing an article on the HubPages Service.
      Statistics
      Author Google AnalyticsThis is used to provide traffic data and reports to the authors of articles on the HubPages Service. (Privacy Policy)
      ComscoreComScore is a media measurement and analytics company providing marketing data and analytics to enterprises, media and advertising agencies, and publishers. Non-consent will result in ComScore only processing obfuscated personal data. (Privacy Policy)
      Amazon Tracking PixelSome articles display amazon products as part of the Amazon Affiliate program, this pixel provides traffic statistics for those products (Privacy Policy)
      ClickscoThis is a data management platform studying reader behavior (Privacy Policy)