Modal vs. Modeless

To support the different ways that applications use dialog boxes, PowerBASIC provides two types of dialog box: modal and modeless.

A modal dialog box requires the user to supply information, or cancel the dialog box, before allowing the application to continue. Applications use modal dialog boxes in conjunction with commands that require additional information before they can proceed.

A modeless dialog box allows the user to supply information and return to the previous task without closing the dialog box. Modal dialog boxes are simpler to manage than modeless dialogs because they are displayed, perform their task, and are destroyed by calling a single DIALOG SHOW MODAL statement.

In the above example, we display the dialog as modal. The DIALOG SHOW MODAL statement displays the dialog and waits until your code calls DIALOG END (or if there is a Close box in the caption, the dialog will end when the Close box is clicked). When Windows displays a modal dialog box, it disables the parent window to keep the user focused on the dialog. When the dialog box is closed, the parent window is automatically re-enabled.

By comparison, a modeless dialog box does not cause your code to stop and wait while the dialog is displayed. An example of a modeless dialog box is the "Cancel" dialog displayed by many programs that print long documents on the printer. The application code sits in a loop sending data to the printer. The "Cancel" dialog allows the user to cancel printing at any time. The following is a simplistic example of this process:

DIALOG SHOW MODELESS hDlg TO lResult&

DO

  DIALOG DOEVENTS

  Done& = PrintNextLineFunction()

LOOP UNTIL lResult& = %IDCANCEL OR Done& = %TRUE

The DIALOG DOEVENTS statement is necessary so that Windows can process messages for your modeless dialog. Without it, events such as clicking on the "Cancel" button or redrawing the dialog would not be processed. This loop is known as a Message Pump.

A modeless dialog must always have a message pump running while the dialog is running. Without a message pump, a modeless dialog will not be able to receive messages to redraw itself, etc.

Because of this consideration, applications should be written in such a way as to ensure that the message pump is able to run. The following example is of a modeless dialog message pump that relies on the fact that when the dialog is destroyed, DIALOG GET SIZE will return 0.

DIALOG SHOW MODELESS hDlg TO lResult&

DO

  DIALOG DOEVENTS

  DIALOG GET SIZE hDlg TO x&, y&

LOOP UNTIL ISFALSE (x& * y&)

This works fine for applications that have a single modeless dialog showing at any given moment, but this is not always practical. For example, consider an application that uses a tabbed dialog. Typically, this is constructed around a single dialog containing a "Tab Control", plus an additional set of modeless dialogs, each of which would form a "page" of the tabbed dialog.

In this case, we need to reconstruct our message pump so that it terminates only when all of the modeless dialogs have been destroyed. If the main dialog is modal, the application design would become quite complex - the modeless dialogs and the message pump would need to be launched from within the main dialog's Callback Function. Such an approach is technically feasible, but unnecessary. By changing the main dialog from modal to modeless, the whole design can be simplified to use a single message pump.

DIALOG SHOW MODELESS hMainDlg TO lResult&

DIALOG SHOW MODELESS hPage1

DIALOG SHOW MODELESS hPage2

...

DO

  DIALOG DOEVENTS TO Count&

LOOP UNTIL ISFALSE Count&

 

See Also

Dynamic Dialog Tools (DDT)

Creating a Dialog

Adding Controls to the Dialog

Controls

Control Styles

Callbacks

Dialog Styles

Menus