Progress
Language Tutorial
for Character
Using Multi-frame Interfaces
Multi-frame can mean two different things. First, it could mean that you have more than one active frame in a window. Second, it could mean that a window has several different frames, each one appropriate for a different mode or task of the main interface.
Also, you can choose from two basic methods of organizing multiple active frames in a window:
- Defining all the frames as independent siblings that are child widgets of the window.
- Defining frame families (see "Programming the Progress Way"), where at least one frame is a parent that contains all the other frames as its child widgets.
In general, frame families solve a number of problems related to navigation and control in multiple frame interfaces. Among these are tabbing and conditional display. However, some code management is equally necessary for frame families and independent frames.
Tabbing in Multi-frame Windows
While there are several keyboard functions available to help a user navigate through an interface, most users rely on the TAB function. From a user’s viewpoint, TAB moves input focus to the next widget in the interface. From a technical viewpoint, TAB moves input focus to the next widget in the frame. So, if you have two independent frames on screen, the user cannot get to the second frame by using the TAB key. Input focus cycles within the first frame. The user needs to invoke the NEXT-FRAME key function to move focus to another frame.
One way to avoid this problem is to write a trigger that simulates the response the user expects. When the user presses TAB in the last widget of a frame, you can suppress the default behavior and apply the NEXT-FRAME event function to the frame. This moves input focus to the first widget of the next frame. Here is an example:
However, a simpler method is to include all the frames in a single frame family. With this approach, all tabbing behavior is built in. The user can tab among all the frames contained by the parent frame. Focus automatically moves to the first or last field-level widget in the next or previous frame, respectively.
Storing Many Frames
You can design several frames, one for each task that the user can accomplish from the main interface. It might be helpful to store each of these frames in a separate file. They can be stored as include files or as runnable modules (if you included the executable code that goes with the frame). The Progress AppBuilder stores runnable interface code in procedure files with a .w extension. You can adopt this convention to help keep your files organized.
Frame Scoping
Just like records, frames have a life span, and that life span is referred to as the frame scope. The general rules for frame scope are:
If you violate these rules, Progress will notify you at compile time. In general, you won’t need to worry too much about frame scope because the code techniques used with the event-driven programming model tend to scope all frames to a procedure block. Because the frames are scoped to the procedure block, all references to the frame within the procedure block are legal.
One of the more common scoping problems involves trying to reference a frame used by a control block from the main procedure. Here’s an example:
This is invalid code because of the attempt to reference Frame2, which is scoped to the FOR EACH block, outside of that block. If you need to reference the frame in both blocks, you have to make sure that the first reference is in the block that contains the FOR EACH block. The DEFINE FRAME statement is not considered a reference.
For more information on frame scoping, see the Progress Programming Handbook .
Accessing Frame Attributes
Like other widgets, frames have attributes that you can access, but the syntax for accessing a frame attribute is a little different. This is the normal widget attribute syntax.
For frames, this is the syntax.
Table 12–2 describes some of the basic frame attributes that you may want to reference.
Hiding Frames
In "Programming the Progress Way," you learned about using the VIEW and HIDE statements. These two statements operate on the VISIBLE attribute, which all widgets have. The VISIBLE attribute is TRUE if the widget is currently visible in the display, and FALSE if it is not. It is sometimes useful to access the VISIBLE attribute directly to make widgets appear and disappear. VISIBLE does not give you complete control over a widget visibility, however, because Progress has default behaviors that can make a widget visible, even if you made it invisible. For example, displaying a frame makes all the widgets in that frame visible, including any child frames.
Progress provides the HIDDEN attribute to allow you to suppress implicit viewing of a widget. So to make a widget completely invisible, set VISIBLE to FALSE and HIDDEN to TRUE.
The HIDDEN attribute can be used to give your application a significant performance boost. When you start an application, or switch to a new interface within an application, the computer periodically redraws the screen. If the computer redraws the screen several times while you are still setting up the interface, you slow down the appearance of that interface to the user.
Use the HIDDEN attribute on a frame (or window) to make the frame immune to Progress implicit viewing behaviors. If the frame is invisible, so are all the widgets in the frame. With HIDDEN set to TRUE, you can populate a frame with widgets, display data in the frame, and enable the widgets without the frame becoming visible. Then when the frame is ready, use the VIEW FRAME statement to make the interface visible.
Here is an example of the HIDDEN attribute:
In the first case, if the frames are stored separately as include files, then those frames need to be scoped to the main procedure so they are available. As mentioned earlier, in large applications this can make the main procedure overly large.
For runnable code modules, you can use external procedures that use the main interface (as opposed to a dialog box).
Enabling Input in Frame Families
Typically, to enable all field-level widgets in a frame for input, you only have to execute a single ENABLE statement as shown in the following code fragment:
However, if this frame contains child frames that own some of the input widgets you want enabled, these input widgets do not become enabled by this single statement. You must enable input for each frame separately, even though they are in a single frame family:
While this might seem like unnecessarily redundant code, it does afford a measure of control where you choose to group input fields within child frames by common function. You might then enable and disable each child frame (group of fields) under the parent frame according to input received by fields owned by the parent frame itself.
Copyright © 2004 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095 |