Command Button

 

Introduction

A Button is a Windows control used to initiate an action. From the user’s standpoint, a button is useful when clicked, in which case the user positions the mouse on it and presses one of the mouse’s buttons.

There are various kinds of buttons. The most common and regularly used is a rectangular object that the user can easily recognize. In some programming environments, this classic type is called a Command Button. There are other controls that can serve as click controls and initiate the same behavior as if a button were clicked.

From the programmer’s standpoint, a button needs a host, such as a dialog box. To add a button to a dialog box, click it on the Toolbox and click in the desired location on the dialog box.

By default, when you visually create a dialog box, Microsoft Visual C++ adds two buttons: OK and Cancel

Buttons Properties and Methods

The most popular button used in Windows applications is a rectangular control that displays a word or a short sentence that directs the user to access, dismiss, or initiate an action or a suite of actions. In Visual C++ applications, this control is implemented using the Button control Button from the Toolbox window.

To add a button to an application at design time, from the Controls toolbox, click the Button button and click the desired area on the form or dialog box. If you plan to refer to the button in your code, for example to change its caption or some other properties, you should add a Control Variable for it. You could call it m_Button.

Like every Window control, a button is recognized by its IDentifier. Because a button is a control, by convention, its identifier's name starts with IDC (the C stands for Control). The whole name of the identifier can be in lowercase or a mix of lowercase and uppercase but it is better to make it uppercase.

A control's identifier is mainly used for resource purposes, although it can also be used to refer to a control. Otherwise, if you will be calling a control to access its properties or events, you should declare a global variable from it. To do this, in MSVC 6, you can access the ClassWizard dialog box and, in the Member Variables property page, double-click the button, specify a name, making sure that the variable is declared as a CButton and click OK. In MSVC .Net, simply right-click the button and click Add Variable. Give the desired name, making sure that the variable is declare as a CButton and click Finish. Although you can use its identifier to refer to an existing control, the associated variable is declared in the CDialog class and can be accessed anywhere.

To programmatically create a button, declare a variable or a pointer to CButton using the its default constructor. If you plan to use the button to access various member functions or variables of its parent window, you should declare it in the class. To initialize the control, call its Create() method. Here is an example:

class CExerciseDlg : public CDialog
{
// Construction
public:
	CButton *pButton;
	CExerciseDlg(CWnd* pParent = NULL);	// standard constructor
	...
}
CExerciseDlg::CExerciseDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CExerciseDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CExerciseDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	pButton = new CButton;
}

. . .

/////////////////////////////////////////////////////////////////////////////
// CExerciseDlg message handlers

BOOL CExerciseDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	pButton->Create("&Submit", WS_CHILD | WS_VISIBLE,
		            CRect(150, 20, 250, 43), this, 0x302);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

If you dynamically create a button instead of visually adding it, you would have to write all of its messages manually.

From the user’s point of view, the only things important about a button are the message it displays and the action it performs. The word or sentence that displays on top of a button is its Caption. By default, after adding a button to a form, the Caption property has focus. Therefore, if you start typing, the caption would be changed. At design time, you can set the caption with the necessary string on the Caption field of the Properties window. At run time, to change the caption of a button, call the CWnd::SetWindowText() method and pass it the necessary string as argument. Here is an example:

BOOL CDialog5Dlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	m_Submit.SetWindowText("Submit");

	return TRUE;  // return TRUE  unless you set the focus to a control
}

If you want to access the properties of a control without using an associated variable, you may have to call the CWnd::GetDlgItem() method. It comes in two versions as follows:

CWnd* GetDlgItem(int nID) const;
void CWnd::GetDlgItem(int nID, HWND* phWnd) const;

When calling this method, the first version allows you to assign a CWnd (or derived class) to it. The second returns a handle to the window passed as pointer. In both cases, you must pass the identifier of the control that you want access to. When using the first version, if the control is not a CWnd object, you must cast it its native class. Then you can manipulate the property (or properties) of your choice. Here is an example that accesses a button and changes its caption:

BOOL CDialog5Dlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	m_Submit.SetWindowText("Submit");

	CButton *btnWhatElse = reinterpret_cast<CButton *>(GetDlgItem(IDC_BUTTON3));
	btnWhatElse->SetWindowText("What Else?");

	return TRUE;  // return TRUE  unless you set the focus to a control
}

The second version requires a pointer to a child window that you want to access. 

The most popular button captions are OK and Cancel.

The OK caption is set for a dialog box that informs the user of an error, an intermediary situation, or an acknowledgement of an action that was performed on the dialog that hosts the button. Visual C++ makes it particularly easy to add an OK button because in Windows applications, the OK object has a special meaning. To use an OK button, add a button to a form and, from the ID combo box, select the IDOK identifier. What makes this constant special is that the MFC recognize that, when the clicks it, if the dialog box is modal, the user is acknowledging the situation. If this dialog box was called from another window using the DoModal() method, you can find out if the user had clicked OK and take further action. Therefore, when the user clicks OK, the dialog box calls the OnOK() method. Its syntax is:

virtual void OnOK();

Although it looks like a simple method (and it is) the OnOK() carries the constant value IDOK that you can use as a return value of the DoModal() method. Therefore, in one step, you can use the DoModal() method to display a modal dialog box and find out whether the user clicked OK. We will see various examples of this situation in this book.

When a dialog box is equipped with an OK button, you should allow the user to press Enter and perform the OK clicking. This is taken care of by setting the Default Button property to True or checked.

The Cancel caption is useful on a button whose parent (the dialog box) would ask a question or request a follow-up action from the user. A cancel button is also easy to create by simply adding a button to a dialog box and selecting IDCANCEL as its identifier in the ID combo box. Setting a button's identifier to IDCANCEL also allows the user to press Esc to dismiss the dialog box.

The scenarios described for the OK and the Cancel buttons are made possible only if the compiler is able to check or validate the changes made on a dialog box. To make this validation possible, in your class, you must overload the CWnd::DoDataExchange() method. Its syntax is:

virtual void DoDataExchange( CDataExchange* pDX );

This method is used internally by the application (the framework) to find out if data on a dialog box has been changed since the object was displayed. This method does two things it ensure the exchange of data among controls and it validates the values of those controls. In reality, it does not inherently perform data validation, meaning it would not allow or disallow value on a control. Instead, the compiler uses it to create a table of the controls on the dialog box, their variables and values, allowing other controls to refer to it for data exchange and validating. If you want to find out the data a user would have typed or selected in a control, you would have to write the necessary code.

By default, the caption on a button is positioned in the middle and the center of the control. At design time, you can control this position using the Horizontal and the Vertical Alignments on the Properties window:

  Top caption alignment  
Left caption alignment Default caption alignment Right caption alignment
  bottom caption alignment  
      Horz Align: Default
Vert Align:  Top
 
Horz Align: Left
      Vert Align:  Default
Horz Align: Default or Center
Vert Align:  Default or Center
Horz Align: Right
    Vert Align:  Default
  Horz Align: Default
Vert Align:  Bottom
 

After creating a control, to make sure that it displays when its host control comes up, set its Visible property to True or checked (the default). Otherwise, if you want it to be hidden for example to wait for an intermediary action from the user, you can set its Visible property to False or unchecked. For example, to display a control, whether it is hidden or not, call the CWnd::ShowWindow() method and pass SW_SHOW as its argument:

BOOL CDialog5Dlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	m_Submit.ShowWindow(SW_SHOW);
	return TRUE;  // return TRUE  unless you set the focus to a control
}

In the same way, to hide a control, call it by passing the SW_HIDE constant as argument.

For the user to be able to use a control such as clicking a button, the control must allow it. This characteristic of Windows objects is controlled by the CWnd::EnableWindow() method. Its syntax is:

BOOL EnableWindow(BOOL bEnable = TRUE);

This method is used to enable or disable a control. The default value of the argument bEnable is set to TRUE, which would display a control. To disable a control, set the argument to FALSE. Here is an example:

void CDialog5Dlg::OnLetItBe() 
{
	// TODO: Add your control notification handler code here
	m_Submit.EnableWindow(FALSE);
}

Buttons Messages

The most regular action users perform on a button is to click it. When a user does this, the button sends a BN_CLICKED message. In some but rare circumstances, you may also ask the user to double-click a button. Over all, you will take care of most message handling when the user clicks a button.

There are other messages that you can handle through a button.

To close a dialog box, you can use the Win32 API's PostQuitMessage() function. Its syntax is:

VOID PostQuitMessage(int nExitCode);

This function takes one argument which is an integer. The argument could be set to almost any integer value although it should be WM_QUIT. Here is an example:

void CDialog5Dlg::OnBtnClose() 
{
	// TODO: Add your control notification handler code here
	PostQuitMessage(125);
}

Although the MFC provides enough messages associated with the various controls, in some circumstances you will need use a message that is not necessarily associated with the control. In such a case, you can call the CWnd::SendMessage() method. Its syntax is:

LRESULT SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);

The first argument of this method can be a Win32 message or constant.  Examples would be WM_CLOSE or WM_ACTIVATE. The wParam and lParam arguments can be additional (Win32) messages.

The WinExec() function is used to run an application. Its syntax is:

UINT WinExec(LPCSTR lpCmdLine, UINT uCmdShow);

The lpCmdLine argument specifies the name or path of the application you want to display. The uCmdShow specifies how the application should be displayed. It uses the same values as the CWnd::ShowWindow() method.

Related Articles:

Net Price
Calling one Dialog from Another
Strings in Dialog Box Controls
Dialog Data Transfer
 

Copyright © 2003-2005 FunctionX, Inc.