A Second Dialog


A second dialog is the topic of this section. This dialog is more comprehensive than the first and provides an example of managing radio buttons. A snapshot of the dialog in action is shown below.

The application consists of:

The About2 box has two groups of radio buttons. One group is used to select the color in which to paint both the client and the sample color on the dialog box; whilst the other group selects between an ellipse and a rectangle (for both the dialog and the client). The rectangle or ellipse within the dialog is updated as the selections are made; while the client is updated with the new selection only if the dialog is dismissed with the ok button. If the dialog is dismissed with the cancel button, the existing selections are discarded and the client remains as it was.

Methods of Dismissing a Dialog

The main program displays the dialog when it receives the notification message::command - as shown below.

case message::command:
 switch (low_part(parameter1))
  {
   case MenuItemAbout:
    if (dialog_box(get_module_handle(0),
                  DialogIdentity,
                  window_handle,
                  About))
      invalidate_rectangle(window_handle,(const rectangle*)null,true);
    break;
  }
 break;

If the dialog is dismissed via the ok button, the function dialog_box returns true. In this case, the window is invalidated - because the values of the fields current_color and current_figure may have been changed - resulting in the new figure and color being drawn. Whether these fields are updated depends upon the method of dismissal, as shown in the portion of the dialog displayed below.

    case message::command:
    {
        dialog_data* data = (dialog_data*)get_window_pointer(dialog_handle, offset::user_data);
        switch (low_part(parameter1))
        {
        case item_identity::ok:
        {
            handle parent = get_parent(dialog_handle);
            window_data* wdata = (window_data*)get_window_pointer(parent, 0);
            wdata->current_color = data->color;
            wdata->current_figure = data->figure;
            end_dialog(dialog_handle, (void*)true);
        }
        return (result)true;
       ...
      }
     break;

If the dialog is dismissed with the cancel button, false is passed as the second parameter of a call to end_dialog, resulting in the function dialog_box returning false back in the client window procedure. In this case, the local variables color and Figure are not copied to the fields current_color and current_figure. If the Ok button was used to dismiss the dialog, the local variables are copied to their global counterparts and true is set as the second parameter of the call to end_dialog. This causes the call to the function dialog_box that initiated the dialog to return true.

The Layout of Controls within a Dialog

The primary purpose of the dialog under discussion is to update the global variables CurrentColor and CurrentFigure. The local variable color is related to one group of radio buttons; whereas, the local variable Figure is related to the other group of radio buttons. These buttons have been grouped in the resource file. For example, the color buttons were declared within a group via the following statements.

GROUPBOX    "&color"   -1,           4,  50,  54, 112
RADIOBUTTON "&Black"   ButtonBlack,  8,  60,  40,  12, WS_TABSTOP | WS_GROUP
....

The group box is the rectangle surrounding the radio buttons for color (in the above snapshot). The text of the group box also appears in that snapshot. The identities of the buttons that form this group have been arranged consecutively. The other group box is shown below.

GROUPBOX    "&Figure"      -1,              68, 120,  60,  40, WS_GROUP
RADIOBUTTON "Rec&tangle"   ButtonRectangle, 72, 134,  50,  12, WS_TABSTOP | WS_GROUP
RADIOBUTTON "&ellipse"     ButtonEllipse,   72, 146,  50,  12

The first button in each group has the style WS_TABSTOP (style::Tabstop). This implies that the tab key may be used to tab into the group. Only the first item of each group has this style. The up and down arrow keys may be used to manipulate the focus within the group.

Radio buttons are used for mutually exclusive options. That is, only one radio button in the group should be checked. To set the check for a radio button within a group, a special function has been supplied by windows: check_radio_button. This function selects a new item within a group of radio buttons and deselects the item currently selected. This is fortunate; otherwise a for loop would be required if only the button message button_message::set_check was available. In such a for loop, the function get_child_window would be required to obtain a handle of each button. The message button_message::set_check would then be used to check or uncheck individual buttons. The function check_radio_button does all this in one statement. The function check_radio_button occurs in four places - twice during the processing of the message message::initialize_dialog and twice (in different circumstances) upon receiving the command notification. The initialization portion of the dialog is shown below.

    case message::initialize_dialog:
    {
        dialog_data* data = new dialog_data();
        set_window_pointer(dialog_handle, offset::user_data, (void*)data);
        window_data* wdata = (window_data*)parameter2;
        data->color = wdata->current_color;
        data->figure = wdata->current_figure;
        check_radio_button(dialog_handle, ButtonBlack, ButtonWhite, data->color);
        check_radio_button(dialog_handle, ButtonRectangle, ButtonEllipse, data->figure);
        data->control = get_child_window(dialog_handle, TextPaint);
        set_focus(get_child_window(dialog_handle, data->color));
    }
    break;

Values for color and Figure are copied from their global counterparts. These are set as the initial selections. Included in the initialization is a statement that obtains the handle of the static used to display the current color and shape (control). The appropriate radio buttons are selected. The focus is also set. When the focus is set in this manner, the dialog should return false (which it does in this case). If the dialog determines that the operating system chooses the control with the focus, it should return true from the message message::initialize_dialog.

When the buttons are selected via operator interaction, the notification message::command is received by the dialog. The notifications for the buttons are shown below.

case message::command:
 switch (low_part(parameter1))
  {
   ....
   case ButtonBlack:
   case ButtonRed:
   case ButtonGreen:
   case ButtonYellow:
   case ButtonBlue:
   case ButtonMagenta:
   case ButtonCyan:
   case ButtonWhite:
    color = low_part(parameter1);
    check_radio_button(dialog_handle,ButtonBlack,ButtonWhite,low_part(parameter1));
    PaintBlock(Control,color,Figure);
    return true;

   case ButtonRectangle:
   case ButtonEllipse:
    Figure = low_part(parameter1);
    check_radio_button(dialog_handle,ButtonRectangle,ButtonEllipse,low_part(parameter1));
    PaintBlock(Control,color,Figure);
    return true;
  }
  break;

For both sets of buttons, the function check_radio_button is called to check the appropriate button. In both cases the function PaintBlock is called to paint the display control according to the new values that have been set.