Chapter 6 Child Window Controls

Chapter 4 showed programs in the CHECKER series that 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. As you played with the program, you may have thought that the rectangle with the X inside looked vaguely familiar. If the rectangle were reduced in size, it would resemble a ”check box“ that Windows programs use in dialog boxes to allow the selection of options.

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 called ChildWndProc. If we wanted to, we could add a facility to ChildWndProc 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) ;

Perhaps for this message the child window could set wParam to its child window ID. The lParam could be set to a 1 if the child window were being checked and a 0 if it were being unchecked.

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 an input device for the parent window.

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 child window controls. 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 about 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 10, 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 overlapped 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.

When you bring up your normal 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 one of these names: ”button,“ ”static,“ ”scrollbar,“ ”edit,“ ”listbox,“ or ”combobox.“ 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 relinquish the input focus back to the parent window. This is a problem we'll struggle with throughout this chapter.