Win32 Dynamic User Interface Trick

Using the Windows API to Generate the UI Dynamically at Run Time

© Guy Lecky-Thompson

A Win32 API tutorial on creating dynamic user interfaces for wizards, polls, training and other applications needing an interface that changes at run time.

Introduction

Building an application that has a dynamic user interface is a very useful technique to be able to master. Anything from programmable button bars, wizard interfaces, polls, teaching and training software can benefit from a dynamic user interface. Generally speaking, a dynamic GUI consists of:

Each of these can be created dynamically, and can also be manipulated at run-time, using some simple Windows API calls. In fact, the manipulation of graphical user interface objects is key to the Win32 programming paradigm. There are 3 techniques used to manipulate the dynamic user interface:

We shall study each of these in turn and see how a dynamic user interface is built up by creating a series of child windows.

Using the CreateWindow Call

In Win32 API programming, a window is created with the CreateWindow call, and destroyed with the DestroyWindow. The handle returned by the CreateWindow call is a specific reference to that window, and is required by the DestroyWindow call to know which window is to be destroyed.

The CreateWindow function takes 11 parameters, and since we are creating child windows, some of these can be set to default or known values:

CreateWindow(
LPCSTR szClassName, // Either "edit", "button", "combobox", or "static"
LPCSTR szWindowName, // Can be set to ""
DWORD dwStyle, // Will be a combination of window styles including WS_CHILD|WS_VISIBLE
int nX, nY, nWidth, nHeight, // Positioning information
HWND hParent, // The parent window handle
HMENU nID, // The Identifier
HINSTANCE hInstance, // Global application instance
NULL); // Additional data, not required

The HMENU nID parameter needs some explanation. Usually it is set aside for a handle to the menu, but GUI elements do not have menus, and so it is re-used for the child window identifier, which is an integer. However, since the HMENU and integer types are not directly compatible, it is necessary to cast the integer to an HMENU type in the call. For example, the following code will create 10 child windows (buttons) in the parent window client area:

#define BUTTON_START USER+1000
#define MAX_BUTTONS 10
// The handle pool
HWND hButtonBar[MAX_BUTTONS];
// Get the client area
RECT rcClient;
GetClientRect(hwnd, &rcClient);
// Decide on button dimensions
int nButtonWidth = rcClient.right / 10;
int nButtonHeight = rcClient.bottom / 10;
// Create the buttons
for (int i = 0; i MAX_BUTTONS; i++)
{
char szButtonName[25];
sprintf(szButtonName,"%02d", i);
hButtonBar[i] = CreateWindow( "button", szButtonName,
WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
i * nButtonWidth, 0, nButtonWidth, nButtonHeight,
hwnd, (HMENU) BUTTON_START + i, hInstance, NULL);
}

We have retained the window handle, so we can destroy all the windows in a similar loop using a call such as

DestroyWindow(hButtonBar[i]);

One can also destroy a window by sending it the WM_DESTROY message in some cases, but since this does not clean up menus, timers, and flush the message queue for some windows, it is not advisable.

Intercepting the WM_COMMAND Message

When the GUI element is interacted with, a message is sent to the parent window. This message comes as part of the WM_COMMAND message, as if a menu item was selected. There are some caveats when working with edit, list and combo-boxes, but these are well documented in the Win32 API reference, and on the Microsoft MSDN web site. Generally speaking, processing the notification is easy, requiring a loop-and-test approach:

case WM_COMMAND:
{
for (i = BUTTON_START; i BUTTON_START + MAX_BUTTONS; i++)
{
if (wParam == i)
{
// Process the child window notification
}
}
switch (wParam) // Catch everything else
{
// Process menus, etc.
}
}
break;

Exactly what processing is done in the child window processing is application-dependent.

Showing and Hiding the GUI Elements

If we need to dynamically show and hide the elements, we can call the ShowWindow function. This is easy to use as long as we have positioned the elements correctly:

ShowWindow( hButtonBar[BUTTON_START], SW_HIDE ); // Hide the child window
ShowWindow( hButtonBar[BUTTON_START], SW_SHOW ); // Show the child window

The SW_SHOW flag will restore the child window in its current position. We can use MoveWindow to move it around in between the SW_HIDE and SW_SHOW calls, to arrange the interface behind the scenes.


The copyright of the article Win32 Dynamic User Interface Trick in Windows Programming is owned by Guy Lecky-Thompson. Permission to republish Win32 Dynamic User Interface Trick must be granted by the author in writing.




Post this Article to facebook Add this Article to del.icio.us! Digg this Article furl this Article Add this Article to Reddit Add this Article to Technorati Add this Article to Newsvine Add this Article to Windows Live Add this Article to Yahoo Add this Article to StumbleUpon Add this Article to BlinkLists Add this Article to Spurl Add this Article to Google Add this Article to Ask Add this Article to Squidoo