Control Windows


In chapter 5, an example was given that created 25 child windows (under the guise of performing correlation). Each child window maintained a state that it used to decide whether to draw itself clear or with a cross. These child windows made no attempt to communicate with the parent; although, it could have been so. Imagine that when the child changed its state, it sent the message message::command to its parent to notify of the selection that had been made. To achieve this, the child window could have queried its parent via the function get_parent, then sent the parent a message via function send_message. In doing this, the child could have packed its own identity and handle as parameters so as to conform to the message parameters documented for the command message.

The suggested message identity was message::command, but really it could be any application defined identity. To avoid conflicting with any of the system defined messages, application defined messages usually start at message::user.

When a child window processes mouse and keyboard messages and notifies its parent when its state changes, it is referred to as a control window. In effect, the child window becomes an input device for the parent window.

Although an application may create its own custom controls, the operating system defines certain control windows for use by applications. These are shown in the table below.

button Push buttons, check boxes, radio buttons etc.
combobox Combines an edit field and a list box.
static Static text and icons.
edit Single and multiple line entry fields.
listbox Single and multiple selection list boxes.
scrollbar Horizontal and vertical scroll bars.

System Window Classes

applications usually do not create instances of the above mentioned classes as children of the client (say). Instead, these classes are usually defined within a dialog template created by a dialog editor - or manually coded in a resource file. When controls appear within a dialog, the keyboard logic for switching between controls is handled by the system. Despite this, to gain an appreciation of the classes by themselves, several examples of using these controls directly will be given. In a later chapter, the controls will be included in dialogs - as they normally would be.

So far, client window classes have been registered prior to being used. The window classes for the above controls are preregistered by the system. The class names are strings such as "button", "static", "scrollbar", "edit", "listbox" and "combobox". Whilst the window classes are predefined, the window style bits for each of these classes affect their appearance and operation, as will be seen in the next section.

The button wclass

The button window class has 10 basic styles which give a button window different functionality and appearance. These are shown in the table below.

button style button type
button_style::push_button Push button
button_style::push_button_default Default Push button
button_style::check_box Check Box
button_style::auto_check_box Automatic Check Box
button_style::radio_button Radio button
button_style::auto_radio_button Automatic Radio button
button_style::three_state 3State
button_style::auto_three_state Automatic 3State
button_style::group_box Group Box
button_style::owner_draw Owner draw

The program of this section consists of a header file and a main program source file.

Upon receiving the message message::create, the client window procedure creates the buttons. A portion of the code that does this is shown below.

 case message_create:
 {
        handle device_context = get_device_context(window_handle);
        select_object(device_context, get_standard_object(standard_font::fixed_system));

        text_metrics text_metrics_get;
        get_text_metrics(device_context, &text_metrics_get);

        int width_of_character = text_metrics_get.average_character_width;
        int height_of_character = text_metrics_get.height + text_metrics_get.external_leading;

        release_device_context(window_handle, device_context);

        handle button_handles[number_of_buttons];

        for (int i = 0; i < number_of_buttons; i++)
            button_handles[i] = create_window(L"Button",
                button_array[i].text,
                style::child | style::visible | button_array[i].style,
                width_of_character,
                height_of_character * (1 + 2 * i),
                button_width * width_of_character,
                7 * height_of_character / 4,
                window_handle,
                (handle)i);

        set_window_position(window_handle, 0, 0, 0,
            (button_width + 3) * width_of_character,
            height_of_character * (4 + 2 * number_of_buttons),
            place::no_move | place::no_zorder);

    }
    break;

When the windows are created, the style and the text for the windows are taken from the array declared in the header file. The client window is a popup window and it is given its initial size thereafter.

A snapshot of the program in action is shown below.

Button Notifications

A button notifies its parent of a selection via the command message. The parameters of the message are shown in the table below.

command Notifications
low byte of parameter 1 The identity of child window.
high_part of parameter 1 The notification code.
parameter 2 The window handle of the child.

The child window identity was assigned when the button was created (and it must be unique). The notification codes available for buttons may be found in the enumeration button_notify. Of these, only the notification button_notify::Clicked is current (the other notifications were for user buttons - which are now obselete). The parent responds to button notifications by displaying a message box - as shown in the code fragment below.

case message::command:
 message_box(window_handle,"button Selected","Buttons",message_box_style::ok);
 break;

The remaining code of the sample focuses on drawing the owner-draw button in the display. It merely draws its text and draws a different background when selected. Further discussion of owner draw controls will be presented later in this chapter.

Control Messages

Subsequent to a window being created, the text of the window may be set via the function set_window_text. This function sends the message message::set_text to the window. Conversely, the text of a window may be queried using the function get_window_text - which sends the message message::get_text to the window. The messages message::set_text and message::get_text are general messages that may be applied to many window types. Specific window classes have their own special purpose messages, and the button class is no exception to this rule. A parent may send the following messages to a button child window.

button_message::click Simulates a click on the control with the mouse.
button_message::get_check Obtains the check state of the button.
button_message::set_check Sets the check state of the button.
button_message::get_image Obtains the image for the button.
button_message::set_image Sets the image for the button.
button_message::get_state Obtains the state of the button.
button_message::set_state Sets the highlight state of the button.
button_message::set_style Changes the style of the button.

Child Window Identities

Each child window of a parent has an identity. This identity is assigned when the window is created and it must be unique and non-zero. The window identity is stored in the extra memory (window words) of the window and may be obtained via the following statement.

get_window_integer(window,offset::identity);

System values are stored at negative offsets; whereas, application defined values are stored at non-negative offsets. This technique may be used to query any of the standard or ascribed values in the extra memory of the window. The amount of additional memory contained by a window is determined when the window class is registered. The converse operation of obtaining the handle of a child window given its parent and its identity may be achieved through the function get_child_window.

Push Buttons

The first two buttons that were displayed by the previous example are push buttons. A push button is rectangular and it encloses its text within that rectangle. The text is centered within the boundaries of a push button. Push buttons are used to trigger an immediate action and do not contain any on/off state information like radio buttons and check boxes. A default push button is drawn with a thicker border and behaves slightly differently from a normal push button when placed within a dialog. When enter is used, a default button is activated as the default selection.

When a push button is pressed, the button repaints itself with a 3 dimensional shading effect to yield the appearance of being depressed. When a push button is released after having been depressed, it redraws itself in its undepressed state automatically. When a push button has the input focus, it draws a dotted line surrounding the text. When a push button has the input focus, pressing and releasing the space bar has the same effect as selecting the button with the mouse.

A press of a push button may be simulated by sending it the message:

send_message(button,button_message::set_state,1,0);

whereas the call

send_message(button,button_message::set_state,0,0);

causes the button to return to its normal state. The message button_message::get_state may also be sent to a push button. Because push buttons contain no check state information, the messages button_message::get_check and button_message::set_check may not be used with push buttons.

Check Boxes

Check boxes are squares that may be checked. The text of a check box usually appears to the right of a check box; although, the button style button_style::Textleft may be used to cause the text to be displayed on the left instead. Check boxes are used for selecting a series of unrelated options. They act as toggle switches for those options. Unlike radio buttons, the selection of one check box usually does not affect the selection of other check boxes in a group (unless an application explicitly codes such conduct). Radio buttons differ from this behaviour in that only one radio button within a group is selected and selecting another item deselects the existing item. Radio buttons are therefore used for mutually exclusive selections; whereas, check boxes are good for unrelated toggle selections.

Two different styles exist for check boxes. These are button_style::check_box and button_style::auto_check_box. The difference between these styles of check box may be ascertained by playing with the previous example. An automatic check box checks itself and unchecks itself when selected by the operator (without any help from the owner). A non-automatic check box notifies its owner when it is selected and requires the owner to manually set the state via the message button_message::set_check.

Because an auto check box maintains its own state, the command messages that it generates may be ignored by the owner. Later the check state of the box may be queried.

There are two other styles applicable to check boxes; these are button_style::three_state and button_style::auto_three_state. 3State buttons behave like check boxes but have a third state which is indicated by graying the background of the box. The grayed state may be set via sending the message button_message::set_check with the state parameter equal to button_state::indeterminate.

A check box is aligned with the left edge of its window and is vertically centered in the window. The minimum height for a check box is one character. The minimum width is the number of text characters it contains plus two.

Radio Buttons

A radio button differs from a check box in appearance in that it is drawn with a circle rather than a square. When a radio button is checked, it draws a dot in the center of the circle. Like check boxes, radio buttons have two styles, being button_style::radio_button and button_style::auto_radio_button. Automatic radio buttons should only be used in dialogs. In dialogs, groups of radio buttons are used to indicate a range of mutually exclusive options. For non-automatic radio buttons, upon receiving a command message from the button, the owner should send the message button_message::set_check to update the check state of the button. The check state of any other radio button in the group should be removed.

Group Boxes

The group box button provides a frame into which other buttons may be put. This is especially useful for groups of radio buttons. A group box processes neither keyboard nor mouse input and does not send command messages to the owner.