Consultor Eletrônico



Kbase 15261: Stacked WAIT-FOR statements in a window, frame or dialog box
Autor   Progress Software Corporation - Progress
Acesso   Público
Publicação   10/05/1998
Stacked WAIT-FOR statements in a window, frame or dialog box


When using WAIT-FOR statements in an application, programmers
should take precautions to make sure that only one WAIT-FOR
is "active" at any one time. The PROGRESS 4GL does not
do this kind of housekeeping automatically.


ACTIVE AND INACTIVE WAIT-FORs
-----------------------------

What do we mean by an "active" WAIT-FOR? An active WAIT-FOR
is one where it is possible for the WAIT-FOR's target event to
occur. For example, if a WAIT-FOR is waiting for the
choose of a certain button, and that button is enabled on the
interface, then that WAIT-FOR is said to be active.

For example, consider the following statement:

WAIT-FOR "CHOOSE" OF Ok_btn IN FRAME my_frame.

This WAIT-FOR is said to be active if it is possible for
the "choose" of Ok_btn to occur in the interface. This
includes any "choose" of the button that happens as a result
of a user's mouseclick, a keyboard accelerator, or a
programmatic occurance of an APPLY "CHOOSE" statement.

For this WAIT-FOR *not* to be active, the window or frame where
it resides would have to be in a state where the WAIT-FOR's
target event could not possibly happen. In this example, that
would mean that Ok_btn itself would be disabled.


ONE AT A TIME, FOLKS
--------------------

Why do we want only one active WAIT-FOR at any one time? The
reason is that as WAIT-FOR statements are executed and begin
to block for input, they are saved in a stack. (This is what
is referred to as a "stacked WAIT-FOR" condition.) Whenever
WAIT-FORs are stacked, they must be "unstacked" in the reverse
order from which they were created.

A set of stacked WAIT-FORs is not an inherently bad thing.
In fact, the Progress ADE uses them extensively. Whenever
you run the Procedure Editor and then run the User Interface
Builder without first exiting the Editor, you are creating
a stacked WAIT-FOR condition. The Procedure Editor's WAIT-FOR
(which is satisified by it's "Exit" pull-down menu) and the
UIB's (also satisfied by the "Exit" pull-down) are both
executing. Since you ran the UIB after the Procedure Editor,
its WAIT-FOR is at the top of the WAIT-FOR stack.

What you will notice, however, is that while the UIB
is running on top of the Procedure Editor, it is not
possible to do anything more with the Procedure Editor --
including exiting out of it. This is because the designers
of the ADE took into consideration the fact that only one
WAIT-FOR -- that which applies to the last window created --
should be active at any one time. The Procedure Editor
therefore disables all of its widgets prior to initiating
the RUN statement that starts up the UIB. This had to
be done programmatically and is not an automatic feature
of the 4GL.

When the UIB then exits and returns to the Procedure
Editor, the widgets in the Procedure Editor are newly
enabled. This feature was also programmed specifically
into the ADE tools and is not done automatically by
the 4GL.

Other programs featuring multiple windows should take
similar measures to ensure proper management of the
WAIT-FOR stack. If you fail to make a current WAIT-FOR
inactive before initiating an additional WAIT-FOR
state, users will be able to apply the events that
satisfy a WAIT-FOR in the middle of the stack. This
in turn will generate runtime errors.


WAIT-FORs AT THE WIDGET LEVEL
-----------------------------

In event-driven programs, a WAIT-FOR is typically used to
set up an event wait state for an *entire* frame or window.
Use of a WAIT-FOR at the widget level is greatly discouraged.
For one, it creates an application state where more than
one WAIT-FOR is active: the window's (or frame's) WAIT-FOR
and the WAIT-FOR for the widget. Secondly, it's just plain
bad programming practice since it affects only a portion of
an interface and not an entire window or frame.

A typical error along these lines is to set up a fill-in
widget with a WAIT-FOR that is waiting for a LEAVE event.
Programmers usually come up with such scenarios due to
a mistaken impression that a WAIT-FOR is needed to begin
processing events in an interface. This is not the case.
Instead of using a WAIT-FOR "LEAVE", for instance, the
programmer should use an ON "LEAVE" trigger for the fill-in.

Setting up WAIT-FORs at the widget level will usually result
in runtime errors, again due to the way they expose WAIT-FORs
in the middle of the WAIT-FOR stack to events.


DIALOG BOX WAIT-FORs
--------------------

A dialog box is a special case where the windowing system
will manage stacked WAIT-FORs for you. Since a dialog box
is modal, it prevents any interaction with other parts of an
application until its WAIT-FOR has been satisfied (although
it is possible to create an additional dialog box on top
of an existing one.) This modal property of dialog boxes
is the reason they are most recommended for any database
transaction programming.


CONCLUSION
----------

The basic rules are:

(1) Deactivate previous WAIT-FORs before executing any code
which establishes an additional WAIT-FOR state. Do this
mainly by disabling widgets. Remember to include code
to re-enable the widgets once the WAIT-FOR is back at
the top of the stack again.

(2) Make sure all WAIT-FORs are scoped to the window or
frame level and not to the widget level.

(3) Use dialog boxes for all database transactions.

If it is imperative that more than one window be active in
your application at one time, then use persistent procedures
rather than windows created with WAIT-FORs.

Progress Software Technical Support Note # 15261