[ Next ] [ Previous ] | Chapter 13 |
Dialog boxes are designed to gather specific
pieces of information from
the user. Dialog contain a mix and match of child control windows. A
window
that pops up and contains such fields as "Name:", "Address", "Phone",
"City",
and "State", is a good example of a dialog box.
|
![]() |
Dialog boxes come in two styles - modal and modeless. A modeless
dialog
box lets the user interact with all the other windows and controls
belonging
to the same process. A modal dialog box is more restrictive of the
user's
input. A user cannot interact wish the other windows and controls that
are children of the owner of the dialog box, including the owner. A
modal
dialog box is designed to be used when the user is required to enter
some
information before proceeding on to the next step in the application.
The following sample program is designed to introduce dialog box
programming
and to display the difference between modal and modeless dialog boxes.
DIALOG.C
|
![]() Dialog.exe - Modeless dialog example |
The resource file, DIALOG.RC, is the starting point for the sample program. Two items are defined in the file, a menu and the dialog box. The resource file for the window shows the menu that we would like displayed in our client window. For more information on resources, see Chapter 12.
The following is the resource definition to create the dialog boxes used in the DIALOG.C program.
DLGTEMPLATE IDD_DIALOG LOADONCALL MOVEABLE DISCARDABLE
{
DIALOG "Dialog example", IDD_DIALOG, 53, 28, 260, 55,
WS_VISIBLE,
FCF_SYSMENU | FCF_TITLEBAR
{
LTEXT "?", IDT_DIALOGNAME, 10, 40, 150, 8
LTEXT "?", IDT_CLICK, 10, 30, 150, 8
DEFPUSHBUTTON "OK", DID_OK, 10, 10, 50, 13
}
}
The dialog IDD_DIALOG is created in the resource file as visible, with
a system menu and title bar.
The next step is to define the controls that are to appear on the
dialog
box In this example only an "OK" pushbutton and some static text will
be
used. The IDT_CLICK text will be used to communicate some instructions
to the user. The IDT_DIALOGNAME is used to specify whether this is a
modal
or
modeless dialog box.
The client window procedure, ClientWndProc, is not very
big. A window word is used to store some information that we will
need later in the dialog procedure. This information is stored in a
DLGINFO
structure. The structure includes the structure size, a BOOL variable
to
indicate whether the user selected modal or modeless from the menu, the
handle of the modeless dialog box, and the handle of the client window.
This structure is allocated in the WM_CREATE processing, and cleanup is
done in the WM_DESTROY processing.
The programmatic differences between a modal and nonmodal dialog box
exist in the processing of the WM_COMMAND message.
In our WM_COMMAND processing, we first find out who is sending us the
WM_COMMAND message. The resource ID for the sender is located in mpParm1.
If the user selected "Modal Dialog Box", IDM_MODAL is returned in
mpParm1.
A Boolean variable, pDlglnfo->bModal, is used to indicate to
the
DlgProc whether the user selected a modal or
modeless
dialog box.
The function WinDlgBox is used to create a modal dialog box.
ULONG APIENTRY WinDlgBox(HWND hwndParent,
HWND hwndOwner,
PFNWP pfnDlgProc,
HMODULE hmod,
ULONG idDlg,
PVOID pCreateParams);
When WinDlgBox is used to create a dialog box, a message queue is created for that dialog. User interaction with the other message queue (and the client window associated with it) is held up until the dialog box is dismissed and the message queue is destroyed.
pDlgInfo->bModal = TRUE;WinDlgBox(HWND_DESKTOP,
hwndWnd,
DlgProc,
NULLHANDLE,
IDD_DIALOG,
pDlgInfo);
The first parameter is the parent, HWND_DESKTOP, and the second
parameter
is the owner window, hwndWnd. The programmer almost always will
want to specify the desktop as the parent of a modal dialog, and the
client
window as the owner. If the frame or client was specified as the
parent
of the dialog, the frame window would still be active, thus preventing
the whole purpose of using a modal dialog. The third parameter is the
pointer
to the dialog process function, in this case DlgProc.
NULLHANDLE
tells the system that the resources for the dialog process,
DlgProc,
are located in the .EXE file. IDD_DIALOG is the resource ID for the
dialog.
The last parameter is the data area. This is used to pass programmer -
defined data of type PVOID into the dialog procedure. In this area we
will
pass a pointer to our dialog information structure, pDlgInfo.
WinDlgBox
is actually a combination of four functions,
WinLoadDlg,
WinProcessDlg, WinDestroyWindow, and return.
![]() |
Gotcha! The last parameter to WinDlgBox must be a pointer. This parameter undergoes a procedure called "thunking" that converts a 32-bit pointer into a pointer that is readable by 16'bit code. The application will trap if the value is not a pointer and the system attempts to thunk it. The dialog box functions are l6-bit in OS/2 2.1, and must try and thunk this value. The dialog box functions in Warp are 32-bit, so no thunking will be done; however, if previous versions of the operating system must be supported, it is best to be prepared for thunking. |
pDlgInfo->bModal = FALSE;
if (!pDlgInfo->hwndModeless)
pDlgInfo->hwndModeless = WinLoadDlg(HWND_DESKTOP,
hwndWnd,
DlgProc,
NULLHANDLE,
IDD_DIALOG,
pDlgInfo);
else
WinSetWindowPos(pDlgInfo->hwndModeless,
HWND_TOP,
0,
0,
0,
0,
SWP_SHOW|SWP_ACTIVATE);
In this example, we first set the bModal variable to FALSE to indicate that this will be a modeless dialog box.
![]() |
Gotcha!
A modeless dialog is not destroyed by WinDismissDlg,
only hidden. In order to destroy the dialogs loaded by WinLoadDlg,
WinDestroyWindow must be called
implicitly
for each modeless dialog that has been created. |
The dialog procedure, in this case DlgProc is fairly similar to a window procedure. Our program can use the same dialog process for both the modal and modeless dialog boxes.
![]() |
Gotcha!
One difference between a dialog procedure and a window
procedure is
the default procedure function. A dialog procedure must call WinDefDlgProc
instead of WinDefWindowProc. If a dialog procedure
behaves
irrationally, it should be checked to see if it includes WinDefDlgProc.
These two functions often get interchanged. |
pDlgInfo = PVOIDFROMMP(mpParm2);
The first thing we do is retrieve the information sent to us through the WinLoadDlg or WinDlgBox function. Both these functions will send this information in the message parameter 2 of the WM_INITDLG message.
WinQueryWindowRect(pDlgInfo->hwndClient,
&rclClient);lHeight = rclClient.yTop-rclClient.yBottom;
lWidth = rclClient.xRight-rclClient.xLeft;
In order to make our dialog program prettier, we'll position the two dialogs directly on the client window. However, the parent of the dialogs is the desktop, and remember, the children wilt be positioned relative to the parent. So we do some math. First, we find the height and width of the client area, and use these dimensions to see where the dialogs should be placed relative to the client. We'll start the dialogs at the x coordinate that is 1/8th of the client area width. The y coordinate will differ depending on whether the dialog is the modal dialog or the modeless dialog.
ptPoints.x = lWidth/8;
ptPoints.y = bModal?lHeight/19:lHeight/19*10;
Now that we know where we would put our dialogs if they were placed relative to the client window's coordinate system, all we have to do is find where these coordinates are on the desktop window. And Presentation Manager has a function that will do this for us: WinMapWindowPoints.
BOOL APIENTRY WinMapWindowPoints(HWND hwndFrom,
HWND hwndTo,
PPOINTL aptlPoints,
LONG lCount);
hwndFrom is the handle of the window to map the coordinate
space
from. hwndTo is the handle of the window to map the
coordinate space to. aptlPoints is a point to an array (one or
more)
of POINTL structures that on input contain the coordinates to map and
on
output contain the new coordinates relative to hwndTo. lCount
is the number of structures in the aptlPoints array
In our case, the function looks like this.
WinMapWindowPoints(pDlgInfo->hwndClient,
HWND_DESKTOP,
&ptPoints,
1);
On the function's return, ptPoints will contain the new x and y coordinates relative to the desktop. We use these coordinates as the basis for the WinSetWindowPos function to adjust the size and position of the dialog.
WinSetWindowPos(hwndDlg,
NULLHANDLE,
ptPoints.x,
ptPoints.y,
lWidth/8*6,
lHeight/19*8,
SWP_MOVE|SWP_SIZE);
The WM_COMMAND processing is just like the WM_COMMAND processing for the client window. If the user presses the OK pushbutton, the dialog box is canceled with WinDismissDlg.
Some "features" (actually they really can be nice) can cause problems
in
the future if programmers are unaware of the way WinDefDlgProc
handles WM_COMMAND messages. A dialog will be dismissed if a WM_COMMAND
message is passed to WinDefDlgProc. In some cases, this
makes sense. For instance, if the user presses the OK or CANCEL
pushbuttons,
it would be perfectly logical for the dialog box to go away. However,
if
the other pushbuttons exist, and the programmer does nor want the
dialog
box to be dismissed, WM_COMMAND processing must be intercepted and
return
FALSE, instead of letting the message processing fall through to
WinDefDlgProc. This also means that WinDismissDlg
must be called when the programmer is ready for the dialog to
disappear
and WinDestroyWindow when he or she is ready to
destroy
the dialog box.
WinDismissDlg is also called if a WM_QUIT message
is sent to the dialog.
Dialogs will become an integral part of most of a programmer's Presentation Manager programs. They are easy to use and provide a clean user interface. The main drawback to dialogs is the lack of true device - independent dialog coordinates. Currently, a set of multiple dialogs must be created for different screen resolutions.
[ Next ] [ Previous ] | Chapter 13 |