Release 10.1A: OpenEdge Development:
Progress 4GL Handbook

> ## Extending the sample window to filter dynamically

> You already extended the `h-CustOrderWin4.w` version of the sample window once in Chapter 10, "Using Queries," to filter the records for a particular state. In that version of the procedure, the `LEAVE` trigger on the New State field reopens the Customer query based on the state abbreviation entered:

>     OPEN QUERY CustQuery FOR EACH Customer WHERE Customer.State =
>           cState:SCREEN-VALUE BY Customer.City.

> A static `OPEN QUERY` statement suffices, because the `WHERE` clause is known. The only variable is the state abbreviation, and the procedure can plug that into the `OPEN QUERY` statement.

> You should use the dynamic `QUERY-PREPARE` and `QUERY-OPEN` methods when your procedure needs more flexibility than this. To show how this can work, you can extend the filtering to apply to every field in the Customer table that the window displays. You can change the procedure to let the user filter the Customers based on a value you enter in any of the Customer fields. You can then add a filter button to the window that blanks out the Customer fields and enables them. When the user enters a value in any one of the fields, the code re-prepares and reopens the query to filter on the value for that field.

> | To make these changes:

> 1. Open `h-CustOrderWin1.w` and save it `h-CustOrderWin8.w`.

> 2. Disable all the Customer fields that are displayed.

> Remember that you can select the fields, open the Properties Window, and set Enabled to false for all of them at once. Making them initially disabled allows you to enable them for input only when you want to filter on a value in a field.

> 3. Remove the phrases from the query that filter on `State = “NH”` and sort by City.

> Because the user will be filtering on any field, it makes sense to remove the initial filtering and sorting that this version of the procedure from Chapter 4, " Introducing the OpenEdge AppBuilder." If you double-click on the frame, its property sheet opens where you can access the Query Builder to make the changes. Select the Where and Sort radio set options in turn to make the changes.

> 4. Drop a button onto the frame next to the navigation buttons. Name it btnFilter and give it a Label of Filter.

> 5. Define a `CHOOSE` trigger for the Filter button. The trigger code needs to blank out all the Customer fields and enable them for input.

> What code can you write to do this? The quickest way is to set the `SCREEN-VALUE` of each field to “” and to set the `SENSITIVE` attribute to yes. (Remember that the `SCREEN-VALUE` is the value displayed in the frame and that `SENSITIVE` is the attribute name for the Enabled property of an object.):

>     ASSIGN Customer.CustNum:SCREEN-VALUE = ""
>            Customer.Name:SCREEN-VALUE = ""
>            Customer.Address:SCREEN-VALUE = ""
>            Customer.City:SCREEN-VALUE = ""
>            Customer.State:SCREEN-VALUE = ""
>            Customer.CustNum:SENSITIVE = YES
>            Customer.Name:SENSITIVE = YES
>            Customer.Address:SENSITIVE = YES
>            Customer.City:SENSITIVE = YES
>            Customer.State:SENSITIVE = YES.

> This code certainly works, but does it make you a little uncomfortable? What happens if you later add a field to the frame or remove one? Then you’ve got a maintenance problem on your hands. Try identifying the fill-ins dynamically instead, using what you learned in the previous chapter.

> 6. Define a variable scoped to the procedure to hold the field handles in the Definitions section:

>     /* Local Variable Definitions ---                                       */
>     DEFINE VARIABLE cFillIns AS CHARACTER  NO-UNDO.

> 7. Add code so that the `CHOOSE` trigger builds up a list of all the handles of the objects in the frame that are fill-in fields, if the list hasn’t already been built:

>     DO:
>         DEFINE VARIABLE hContainer AS HANDLE     NO-UNDO.
>         DEFINE VARIABLE hField     AS HANDLE     NO-UNDO.
>         DEFINE VARIABLE iField     AS INTEGER    NO-UNDO.
>         IF cFillIns = "" THEN
>         DO:
>             /* Identify all the fill-ins so they can be enabled, disabled,
>                and cleared. */
>             ASSIGN hContainer = FRAME CustQuery:HANDLE
>                    hContainer = hContainer:FIRST-CHILD. /* The field group */
>             hField = hContainer:FIRST-CHILD.
>             DO WHILE VALID-HANDLE(hField):
>                IF hField:TYPE = "Fill-In" THEN
>                     cFillIns = cFillIns +
>                     (IF cFillIns = "" THEN "" ELSE ",") + STRING(hField).
>                hField = hField:NEXT-SIBLING.
>             END.
>         END.

> 8. Whether the field list has already been built or not, the procedure needs to walk through those fields and blank them and disable them:

>        DO iField = 1 TO NUM-ENTRIES(cFillIns):
>             ASSIGN hField = WIDGET-HANDLE(ENTRY(iField, cFillins))
>                    hField:SCREEN-VALUE = ""
>                    hField:SENSITIVE = YES.
> END.

> Now if you later change the fields on the screen, you won’t have to change this code. That’s part of the value of dynamic programming!

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