Kbase P12116: The WAIT-FOR Statement Explained
Autor |
  Progress Software Corporation - Progress |
Acesso |
  Público |
Publicação |
  15/04/2011 |
|
Status: Verified
GOAL:
The WAIT-FOR Statement Explained
GOAL:
Best practices regarding the WAIT-FOR statement
GOAL:
What is the "one WAIT-FOR golden rule"?
GOAL:
Why should stacked WAIT-FOR statements in a window, frame or dialog box be avoided?
GOAL:
How to avoid error 4122 (Invalid widget handle used in WAIT-FOR statement. WAIT-FOR terminated)
FACT(s) (Environment):
All Supported Operating Systems
Progress 8.x
Progress 9.x
OpenEdge 10.x
FIX:
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 mouse click, a keyboard accelerator, or a programmatic occurrence 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 satisfied 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 im.pression 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.
IMPLEMENTING THE "ONE WAIT-FOR GOLDEN RULE"
Make sure all WAIT-FORs are scoped to the window or frame level and not to the widget level. 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.
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..