|
|
Win32 Dynamic User Interface TrickUsing the Windows API to Generate the UI Dynamically at Run TimeA Win32 API tutorial on creating dynamic user interfaces for wizards, polls, training and other applications needing an interface that changes at run time.
IntroductionBuilding 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 CallIn 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 MessageWhen 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 ElementsIf 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 in print or online must be granted by the author in writing.
|
|
|
|
|
|
|
|