Release 10.1A: OpenEdge Development:
Progress 4GL Handbook

> ## Manipulating the objects in a window

> In this section, you’ll learn how to locate and identify the objects in a window by their handles. Because both static and dynamic objects have handles, and attributes and methods you can manipulate through those handles, this material applies to both static and dynamic objects. Later in this chapter, you’ll add new dynamic objects to the sample window.

> As discussed in the Chapter 14, "Defining Functions and Building Super Procedures," one of the principal reasons why you might need to locate and manipulate objects by their handles is to write generic code to adjust the appearance or behavior of objects from another procedure, such as a super procedure. The sample super procedure `h-WinSuper.p` showed a very simple example of that.

> Next, you’ll write another super procedure to make some more substantial adjustments to the objects in the test window by “walking the widget tree” of the window.

> | To write another super procedure:

> 1. Open the version of `h-CustOrderWin1.w` from Chapter Four as a starting point, as you’ve done before and save it as `h-CustOrderWin7.w`.

> 2. In the main block of `h-CustOrderWin7.w`, add two lines of code, one to use `h-StartSuper.p` to start or locate a new super procedure called `h-dynsuper.p` and the second to run an internal procedure that Progress locates in `h-dynsuper.p`:

>     MAIN-BLOCK:
>     DO ON ERROR   UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
>        ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
>       RUN enable_UI.
>       RUN h-StartSuper.p("h-dynsuper.p").
>       RUN changeFields.
>       IF NOT THIS-PROCEDURE:PERSISTENT THEN
>        WAIT-FOR CLOSE OF THIS-PROCEDURE.
>     END.

> 3. Create a new structured procedure in the AppBuilder.

> 4. Create a new internal procedure called changeFields.

> 5. Define these variables that the procedure needs:

>     /*---------------------------------------------------------------------
>       Procedure changeFields:
>       Purpose:     Locates the fields and browse in the target frame
>                    and changes some of their attributes.
>       Parameters:  <none>
>       Notes:
>     ---------------------------------------------------------------------*/
>     DEFINE VARIABLE hWindow AS HANDLE     NO-UNDO.
>     DEFINE VARIABLE hFrame  AS HANDLE     NO-UNDO.
>     DEFINE VARIABLE hObject AS HANDLE     NO-UNDO.
>     DEFINE VARIABLE hColumn AS HANDLE     NO-UNDO.

> These handles allow you to identify the procedure’s current window, its frame, each field or other object inside the frame, and finally the columns of the order browse in the frame. To understand how to walk down through the frame to locate objects, you need to look at the hierarchy of the objects the handles point to.

> First, look at how a procedure’s window handles are established. Progress defines a single default window for a session, and uses this window to display objects in when no other window is specified. There is a built-in system handle, called `DEFAULT-WINDOW`, that holds the handle of this window. There is also a system handle, called `CURRENT-WINDOW`, that Progress uses as the default for parenting frames, dialog boxes, and messages. Initially, the `CURRENT-WINDOW` is the same as the `DEFAULT-WINDOW`.

> There is no `DEFINE WINDOW` statement in Progress. All other windows in a session are dynamic windows that you create with the `CREATE WINDOW` statement. When you start a procedure, you can set the `CURRENT-WINDOW` system handle to be a window created by your procedure. There is also a `CURRENT-WINDOW` attribute for the `THIS-PROCEDURE` system handle, which holds the procedure handle of the procedure containing the reference to `THIS-PROCEDURE`. Setting the `CURRENT-WINDOW` attribute sets the default parenting for all frames, dialog boxes, and messages used in that procedure without affecting windows defined by other procedures.

> The standard code the AppBuilder uses for a window includes statements to set the `CURRENT-WINDOW` system handle to the dynamic window the AppBuilder code creates, as you saw in Chapter 5, " Examining the Code the AppBuilder Generates." It also sets the `CURRENT-WINDOW` attribute of `THIS-PROCEDURE` to the same window:

>     /* Set CURRENT-WINDOW: this will parent dialog-boxes and frames.        */
>     ASSIGN CURRENT-WINDOW                = {&WINDOW-NAME}
>            THIS-PROCEDURE:CURRENT-WINDOW = {&WINDOW-NAME}.

> Other procedures can access the window of a procedure that adheres to this convention by referencing its `CURRENT-WINDOW` attribute. Therefore, the first thing the `changeFields` procedure does is obtain that window handle. Because it is a super procedure of `h-CustOrderWin7.w`, the `TARGET-PROCEDURE` system handle within `h-dynsuper.p` has the same value as `THIS-PROCEDURE` does within `h-CustOrderWin7.w`:

>     hWindow = TARGET-PROCEDURE:CURRENT-WINDOW.

> If the `h-CustOrderWin7.w` procedure did not set its `CURRENT-WINDOW` attribute, you would need to use some other mechanism to identify it. Because this is the most straightforward way to associate a window with a procedure, you should adopt this convention, whether you use this standard AppBuilder template or not.

> A procedure can create more than one window. Only one window can be the procedure’s `CURRENT-WINDOW`. If your procedures use more than one window, then you need to use some other convention to locate other windows in the procedure. For example, you could store a character string representing a list of other window handles in the window’s `PRIVATE-DATA` attribute. The standard for procedures you build in the AppBuilder, as well as in the SmartObjects that are the components you can build applications from, is to create only one window in a procedure.

> The next level down from a window is the frame or frames that are parented to the window. To identify the first frame in a window, you use its `FIRST-CHILD` attribute:

>     hFrame  = hWindow:FIRST-CHILD.

> If a window has more than one frame, you can access the other frames by following the `NEXT-SIBLING` of the first frame, which chains the frames together.

> As you might expect, you go down to the objects in a frame by accessing its `FIRST-CHILD` attribute. But there is another level of object in between the frame and the fields and other objects in the frame. This level is called a field group.

> Remember that Progress supports the notion of a `DOWN` frame, which displays multiple instances of the same fields to show multiple records from a result set in a manner similar to what a browse does. This visualization is used primarily by older character-mode applications where there is no browse. For this reason most graphical applications use only one-down frames. Regardless of this, the notion of this iteration through multiple instances of the same fields is still present in all frames, and each instance of the fields in the frame is a field group. Therefore, when you reference the `FIRST-CHILD` attribute of a frame, you are accessing its first field group:

>     hObject = hFrame:FIRST-CHILD.   /* This is the field group */

> Unless your frame has a `DOWN` attribute greater than one, the field group is not very interesting in itself. If the frame has more than one field group, you can use the `NEXT-SIBLING` chain to get at each of them. Otherwise, you just proceed down another level to get to the first object in the frame:

>     hObject = hObject:FIRST-CHILD.

> In `changeFields`, you can combine all these steps into a single `ASSIGN` statement:

>     ASSIGN hWindow = TARGET-PROCEDURE:CURRENT-WINDOW
>     hFrame  = hWindow:FIRST-CHILD
>     hObject = hFrame:FIRST-CHILD   /* This is the field group */
>     hObject = hObject:FIRST-CHILD.

> The `ASSIGN` statement is more efficient than a sequence of individual assignments. The steps in the sequence are executed in order, just as they appear. For instance, the value of the `hObject` variable assigned in the third step (to the field group) can then be used in the fourth step to assign the same variable a new value equal to the first object in the group.

> Figure 18–11 is a pictorial representation of how these different objects and their handles are related.

> Figure 18–11: Relationships between objects in a window

Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095