Windows GUI Programming: Subwindows

CS 321 Lecture, Dr. Lawlor, 2006/04/24

Check out the Forger's Windows Tutorial. Also see my example code (Directory, Zip, Tar-gzip).

Try changing the "window class" in your call to CreateWindow to "EDIT".  The "EDIT" window class is prebuilt by Microsoft.  Microsoft calls these pre-registered window classes "controls", and ships them in the DLL "comctl32.dll". Microsoft gives a short list of common "controls" in CreateWindow, or separately a big list of all the builtin "controls".  Unfortunately, documentation on exactly what controls exist, how to create them, and what messages they accept seems to be scattered through the Windows docs.

Window Styles

Several of the builtin controls take parameters at creation time.  These control things like whether the control includes scrollbars, icons, etc.

The EDIT control supports a bunch of window styles.  So we can create a scrolling multi-line edit child window with:
	hEdit1 = CreateWindow("EDIT",
"Starter Text\nWith Newlines...",
WS_CHILD | WS_BORDER | WS_HSCROLL| WS_VSCROLL |
ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE ,
...);

Controlling Controls

After creating a window (such as a control), you can make it do stuff by sending messages directly to its wndProc.  For example, you can select a range of text by passing the EM_SETSEL message:
	// This selects characters 10 through 15.
SendMessage(hEdit1, EM_SETSEL, (WPARAM)10, (LPARAM)15);
There are lots of possible messages you might send to a window.  See the control docs for details.

Control Size

In Windows, you specify the coordinates of any new window's top-left corner (x,y), and the size of the new window (w,h).  For a new control, these coordinates are measured in the containing window.

One of the trickiest parts of GUI programming is keeping the various components of a window in the right locations as the containing window changes size and location.  For example, moving a window causes Windows to pass your wndProc the WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED, WM_MOVE, WM_SIZE, and WM_NCCALCSIZE messages.  You can hook into any of these messages in your wndProc, and respond by shuffling your controls around to match the new window size.

A typical call to move the "hEdit1" window to the bottom half of the enclosing window might look like this:
	int x=0, y=200; // Start of edit window (top left corner)
RECT rc; GetClientRect(hWnd, &rc); // Outside window size
MoveWindow(hEdit1,x,y,rc.right-x,rc.bottom-y,true);
The coordinate calculations for complicated windows can get quite ugly.  This is where a more complicated toolkit (MFC, Qt, Windows Forms, Cocoa, etc.) really shines.

Other Fun Examples

You should definitely try using a BUTTON control.  It's really simple.  When clicked, it delivers a WM_COMMAND to the enclosing window, with wParam equal to the HMENU used when creating the button.

A STATIC control is just some text.  It's really simple.

Possibly the easiest way to make a bunch of child windows is to store them in a DIALOG resource. You can then display the dialog and process events for it with the "DialogBox" routine. See MYDIALOG_ABOUT in the example.

You can even embed Internet Explorer inside a window, although it's tough to do without ATL.  ATL is the "Advanced Template Library", another Microsoft C++ library.  It's similar to, and competes with, their MFC or "Microsoft Foundation Classes".