Working with Dialog Box Controls

In Chapter 6, you discovered that most child window controls send WM_COMMAND messages to the parent window. (The exception is scroll bar controls.) You also saw that the parent window can alter child window controls (for instance, checking or unchecking radio buttons or check boxes) by sending messages to the controls. You can similarly alter controls in a dialog box procedure. If you have a series of radio buttons, for example, you can check and uncheck the buttons by sending them messages. However, Windows also provides several shortcuts when working with controls in dialog boxes. Let's look at the way in which the dialog box procedure and the child window controls communicate.

The dialog box template for ABOUT2 is shown in the ABOUT2.RC resource script in Figure 10-3. The GROUPBOX control is simply a frame with a title (either Color or Figure) that surrounds each of the two groups of radio buttons. The eight radio buttons in the first group are mutually exclusive, as are the two radio buttons in the second group.

When one of the radio buttons is clicked with the mouse (or when the Spacebar is pressed while the radio button has the input focus), the child window sends its parent a WM_COMMAND message with wParam set to the ID of the control. The low word of lParam is the window handle of the control, and the high word of lParam is a notification code. For a radio button, this notification code is BN_CLICKED, or 0. The dialog box window procedure in Windows then passes this WM_COMMAND message to the dialog box procedure within ABOUT2.C. When the dialog box procedure receives a WM_COMMAND message for one of the radio buttons, it turns on the check mark for that button and turns off the check marks for all the other buttons in the group.

You may recall from Chapter 6 that checking and unchecking a button requires that you send the child window control a BM_CHECK message. To turn on a button check, you use:

SendMessage (hwndCtrl, BM_SETCHECK, 1, 0L) ;

To turn off the check, you use:

SendMessage (hwndCtrl, BM_SETCHECK, 0, 0L) ;

The hwndCtrl parameter is the window handle of the child window button control.

But this method presents a little problem in the dialog box procedure, because you don't know the window handles of all radio buttons. You know only the one you're getting the message from. Fortunately, Windows provides you with a function to obtain the window handle of a dialog box control using the dialog box window handle and the control ID:

hwndCtrl = GetDlgItem (hDlg, nID) ;

(You can also obtain the ID value of a control from the window handle by using this function:

nID = GetWindowWord (hwndCtrl, GWW_ID) ;

but this is rarely necessary.)

You'll notice in the ABOUT2.H header file shown in Figure 10-3 that the ID values for the eight colors are sequential from IDD_BLACK to IDD_WHITE. This arrangement helps in processing the WM_COMMAND messages from the radio buttons. For a first attempt at checking and unchecking the radio buttons, you might try something like the following in the dialog box procedure:

static short nColor ;

[other program lines]

case WM_COMMAND :

switch (wParam)

{

[other program lines]

case IDD_BLACK :

case IDD_RED :

case IDD_GREEN :

case IDD_YELLOW :

case IDD_BLUE :

case IDD_MAGENTA :

case IDD_CYAN :

case IDD_WHITE :

nColor = wParam ;

for (n = IDD_BLACK, n <= IDD_WHITE, n++)

SendMessage (GetDlgItem (hDlg, n),

BM_SETCHECK, n == wParam, 0L) ;

return TRUE ;

[other program lines]

This approach works satisfactorily. You've saved the new color value in nColor, and you've also set up a loop that cycles through all the ID values for the eight colors. You obtain the window handle of each of these eight radio button controls and use SendMessage to send each handle a BM_SETCHECK message. The wParam value of this message is set to 1 only for the button that sent the WM_COMMAND message to the dialog box window procedure.

The first shortcut is the special dialog box procedure SendDlgItemMessage:

SendDlgItemMessage (hDlg, nCtrlID, message, wParam, lParam) ;

It is equivalent to:

SendMessage (GetDlgItem (hDlg, nCtrlID), message, wParam, lParam) ;

Now the loop would look like this:

for (n = IDD_BLACK, n <= IDD_WHITE, n++)

SendDlgItemMessage (hDlg, n, BM_SETCHECK, n == wParam, 0L) ;

That's a little better. But the real breakthrough comes when you discover the CheckRadioButton function:

CheckRadioButton (hDlg, nIDFirst, nIDLast, nIDCheck) ;

This function turns off the checks on all radio button controls with IDs from nIDFirst to nIDLast except for the radio button with an ID of nIDCheck, which is checked. The IDs must be sequential. So we can get rid of the loop entirely and use:

CheckRadioButton (hDlg, IDD_BLACK, IDD_WHITE, wParam) ;

That's how it's done in the dialog box procedure in ABOUT2.

A similar shortcut function is provided for working with check boxes. If you create a CHECKBOX dialog window control, you can turn the check mark on and off using the function:

CheckDlgButton (hDlg, nIDCheckbox, wCheck) ;

If wCheck is set to 1, the button is checked; if it's set to 0, the button is unchecked. You can obtain the status of a check box in a dialog box using:

wCheck = IsDlgButtonChecked (hDlg, nIDCheckbox) ;

You can either retain the current status of the check mark as a static variable within the dialog box procedure, or you can do something like this to toggle the button on a WM- COMMAND message:

CheckDlgButton (hDlg, nIDCheckbox,

!IsDlgButtonChecked (hDlg, nIDCheckbox)) ;

If you define a BS_AUTOCHECKBOX control, then you don't need to process the WM_COMMAND message at all. You can simply obtain the current status of the button using IsDlgButtonChecked before terminating the dialog box.