Chapter 9

Child Window Controls

Recall from Chapter 7 the programs in the CHECKER series. These programs display a grid of rectangles. When you click the mouse in a rectangle, the program draws an X. When you click again, the X disappears. Although the CHECKER1 and CHECKER2 versions of this program use only one main window, the CHECKER3 version uses a child window for each rectangle. The rectangles are maintained by a separate window procedure named ChildProc.

If we wanted to, we could add a facility to ChildProc to send a message to its parent window procedure (WndProc) whenever a rectangle is checked or unchecked. Here's how: The child window procedure can determine the window handle of its parent by calling GetParent,

hwndParent = GetParent (hwnd) ;


where hwnd is the window handle of the child window. It can then send a message to the parent window procedure:

SendMessage (hwndParent, message, wParam, lParam) ;

What would message be set to? Well, anything you want, really, as long as the numeric value is set to WM_USER or above. These numbers represent a range of messages that do not conflict with the predefined WM_ messages. Perhaps for this message the child window could set wParam to its child window ID. The lParam could then be set to a 1 if the child window were being checked and a 0 if it were being unchecked. That's one possibility.

This in effect creates a "child window control." The child window processes mouse and keyboard messages and notifies the parent window when the child window's state has changed. In this way, the child window becomes a high-level input device for the parent window. It encapsulates a specific functionality with regard to its graphical appearance on the screen, its response to user input, and its method of notifying another window when an important input event has occurred.

Although you can create your own child window controls, you can also take advantage of several predefined window classes (and window procedures) that your program can use to create standard child window controls that you've undoubtedly seen in other Windows programs. These controls take the form of buttons, check boxes, edit boxes, list boxes, combo boxes, text strings, and scroll bars. For instance, if you want to put a button labeled "Recalculate" in a corner of your spreadsheet program, you can create it with a single CreateWindow call. You don't have to worry about the mouse logic or button painting logic or making the button flash when it's clicked. That's all done in Windows. All you have to do is trap WM_COMMAND messages—that's how the button informs your window procedure when it has been triggered. Is it really that simple? Well, almost.

Child window controls are used most often in dialog boxes. As you'll see in Chapter 11, the position and size of the child window controls are defined in a dialog box template contained in the program's resource script. However, you can also use predefined child window controls on the surface of a normal window's client area. You create each child window with a CreateWindow call and adjust the position and size of the child windows with calls to MoveWindow. The parent window procedure sends messages to the child window controls, and the child window controls send messages back to the parent window procedure.

As we've been doing since Chapter 3, to create your normal application window you first define a window class and register it with Windows using RegisterClass. You then create the window based on that class using CreateWindow. When you use one of the predefined controls, however, you do not register a window class for the child window. The class already exists within Windows and has a predefined name. You simply use the name as the window class parameter in CreateWindow. The window style parameter to CreateWindow defines more precisely the appearance and functionality of the child window control. Windows contains the window procedures that process messages to the child windows based on these classes.

Using child window controls directly on the surface of your window involves tasks of a lower level than are required for using child window controls in dialog boxes, where the dialog box manager adds a layer of insulation between your program and the controls themselves. In particular, you'll discover that the child window controls you create on the surface of your window have no built-in facility to move the input focus from one control to another using the Tab or cursor movement keys. A child window control can obtain the input focus, but once it does it won't freely relinquish the input focus back to the parent window. This is a problem we'll struggle with throughout this chapter.

The Windows programming documentation discusses child window controls in two places: First, the simple standard controls that you've seen in countless dialog boxes are described in /Platform SDK/User Interface Services/Controls. These are buttons (including check boxes and radio buttons), static controls (such as text labels), edit boxes (which let you enter and edit lines or multiple lines of text), scroll bars, list boxes, and combo boxes. With the exception of the combo box, these controls have been around since Windows 1.0. This section of the Windows documentation also includes the rich edit control, which is similar to the edit box but allows editing formatted text with different fonts and such, and application desktop toolbars.

There is also a collection of more esoteric and specialized controls that are perversely referred to as "common controls." These are described in /Platform SDK/User Interface Services/Shell and Common Controls/Common Controls. I won't be discussing the common controls in this chapter, but they'll appear in various programs throughout the rest of the book. This section of the Windows documentation is a good place to look if you see something in a Windows application that could be useful to your own application.