FunctionX - Practical Learning Logo

Property Sheet Buttons

 

Overview

There are two types of property sheets: modal and modeless. A modeless property sheet does not display buttons.

A modal property sheet is equipped with command buttons that allow the user to make a decision after selecting items on the pages or changing the values of the page’s controls. By default, after creating a property sheet, it is equipped with the OK, the Cancel, and the Apply buttons.

By design, the CPropertySheet class, which is the implementer of the property sheet, has a member variable called m_psh. This member represents the PROPSHEETHEADER structure, which is the Win32 implementer of a property sheet. One way you can use the m_psh member variable is to hide the Apply button if you do not need it in your application. Otherwise, this button is available by default on a property sheet.

Here is an example from the Components dialog box of Microsoft Visual Basic:

Description of Buttons Behavior

In this classic design, the functionality of the buttons is commonly standardized:

  • The OK button allows the user to validate any change(s) made on the control(s) of the property page(s) and close the dialog box. For example, if the user changes text from an edit box and clicks OK, the application that called the dialog will have the opportunity to acknowledge the change and act accordingly, and the property sheet would be closed
  • If the user clicks Cancel, the change(s) made on the property page’s control(s) would be discarded, not taken into consideration, and the property sheet would be closed
  • When the property sheet comes up, the Apply button on the property page is disabled. If the user changes something on the controls of the property page(s), the Apply button would become enabled:

Once the Apply button is enabled, the user can use it. If the user clicks the Apply button, 1) any change(s) made on the control(s) is(are) sent to the object that called the property sheet, 2) the Apply button becomes disabled again, 3) the dialog box remains opened.

This description is conform to the standards or suggestions of the Microsoft Windows operating system. In reality, you are completely free to do what you want with the buttons on the property sheet:

  • You can hide them
  • you can display them
  • you can completely delete (destroy) any unneeded button
  • you can add as many buttons as you judge necessary and as the bottom area can afford
  • you can change the captions of the buttons

Buttons Configurations

 

Each control of an MFC application has an identifier. The buttons automatically added to a property sheet are identified as IDOK for the OK button, IDCANCEL for the Cancel button, ID_APPLY_NOW for the Apply button, and IDHELP for the Help button. Therefore, to manipulate any of these buttons, you can call the CWnd::GetDlgItem() method to get a handle to the desired button and do what you want with it. Here is an example code you can use to change the caption of a button, hide another button, or simply destroy another:

BOOL CGeomeSheet::OnInitDialog() 
{
	BOOL bResult = CPropertySheet::OnInitDialog();

	// TODO: Add your specialized code here
	// Change the caption of the OK button
	CButton *btnOK;

	btnOK = reinterpret_cast<CButton *>(GetDlgItem(IDOK));
	btnOK->SetWindowText("Sumbit");

	// Hide the Apply button
	CButton *btnApply;

	btnApply = reinterpret_cast<CButton *>(GetDlgItem(ID_APPLY_NOW));
	btnApply->ShowWindow(FALSE);

	// Destroy the Help button
	CButton *btnHelp;

	btnHelp = reinterpret_cast<CButton *>(GetDlgItem(IDHELP));
	btnHelp->DestroyWindow();

	return bResult;
}

To add a button, declare a pointer to CButton and call its Create() method to initialize. We have seen various examples of how to dynamically create a control. If you decide to dynamically create a button, some of the issues you would have to deal with here are the location and probably the size of the new button, which have little to do with programming but with geometry. Here is an example:

BOOL CGeomeSheet::OnInitDialog()
{
	BOOL bResult = CPropertySheet::OnInitDialog();

	// TODO: Add your specialized code here
	// A pointer to button we will need
	CButton *btnApply;
	// We will need to location and dimensions of the Apply button
	CRect RectApply;

	// Get a handle to the Apply button
	btnApply = reinterpret_cast<CButton *>(GetDlgItem(ID_APPLY_NOW));
	// Get the location and the dimensions of the Apply button
	btnApply->GetWindowRect(&RectApply);

	// Convert the location and dimensions to screen coordinates
	ScreenToClient(&RectApply);

	CButton *Whatever = new CButton;

	Whatever->Create("&Whatever", WS_CHILD | WS_VISIBLE,
			CRect(6, RectApply.top, 85,
			RectApply.top+RectApply.Height()),
			this, 0x188);
			return bResult;

	CFont ctlFont;
	ctlFont.CreateStockObject(DEFAULT_GUI_FONT);
	Whatever->SetFont(&ctlFont, FALSE);
}

Another issue you would deal with is each of the messages sent by your dynamic button.

As seen on the above picture, manipulating one button has no influence on the other(s). For example, if you destroy the Cancel button, the OK button does not move to the right. You would have to reposition any button as you judge it necessary.

We have already mentioned that, by standard and by design, the Apply button is disabled when the property sheet comes up. It is supposed to become enabled once the user gets any control “dirty”, that is, once a control, any control, is not the same as it was when the dialog box came up, the Apply button becomes available. To enable this control programmatically, once a control becomes dirty, call the CPropertyPage::SetModified(). Its syntax is:

void SetModified(BOOL bChanged = TRUE);

This method is called by the control whose value you want to validate once the user has modified it.

When the user clicks the OK button, the CPropertyPage::OnOK() event fires. By design, the changes made on the controls are acknowledged. The controls receive the status of “clean”. The property sheet closes.

When the user clicks the Cancel button, the CPropertyPage::OnCancel() event fires. By design, the changes made on the controls are dismissed. The controls values are kept as they were when the property sheet displayed as long as the user did not previously click Apply since the property sheet was opened. The property sheet closes.

When the user clicks the Apply button, the CPropertyPage::OnApply() event fires. The changes that were made on the controls are acknowledged. The property sheet stays opened.

Once again, these behaviors are the default suggested by the standard but you can change them as you wish, although you should remain with these suggestions because your users may be more familiar with them.

 

 

Copyright © 2003-2007 FunctionX, Inc.