Progress
Programming
Handbook


Using Editing Blocks and User Interface Triggers

This procedure uses an editing block to enable a special key while allowing normal data entry:

p-kystka.p
DEFINE FRAME cust-frame 
     Customer.Cust-num SKIP Customer.name SKIP Customer.address SKIP 
     Customer.address2 SKIP Customer.city Customer.state SKIP  
     Customer.sales-rep HELP "To see a list of values, press F6." 
     WITH DOWN SIDE-LABELS. 
REPEAT WITH FRAME cust-frame: 
   PROMPT-FOR Customer.Cust-num. 
   FIND Customer USING Cust-num.  
   UPDATE Name Address Address2 City State Customer.Sales-rep  
     EDITING: 
        READKEY. 
        IF FRAME-FIELD = "sales-rep" AND LASTKEY = KEYCODE("F6") 
        THEN DO: 
             FOR EACH Salesrep: 
                DISPLAY Salesrep.Sales-rep 
                   WITH NO-LABELS 9 DOWN COLUMN 60 ROW 5. 
             END. 
        END. 
        ELSE DO: 
             APPLY LASTKEY. 
        END. 
     END. 
END. 

This procedure uses an EDITING block on the UPDATE statement. This means that the EDITING block processes every keystroke the user enters while that UPDATE statement is executing. Within the EDITING block, the READKEY statement reads a keystroke from the user. The associated key code is automatically stored as LASTKEY. The procedure uses LASTKEY and the FRAMEFIELD function to determine whether the key is F6, and whether it was entered from within the Salesrep field. If so, it displays a list of all known sales reps. If the key is not F6, or the current field is not the Salesrep field, then the APPLY statement is executed. This causes Progress to handle the keystroke normally.

This procedure uses a user interface trigger in place of the EDITING block to achieve the same functionality:

p-kystkb.p
DEFINE FRAME cust-frame 
     Customer.Cust-num SKIP Customer.name SKIP Customer.address SKIP 
     Customer.address2 SKIP Customer.city Customer.state SKIP  
     Customer.sales-rep HELP "To see a list of values, press F6." 
     WITH DOWN SIDE-LABELS. 
ON F6 OF Customer.Sales-rep 
   DO:  
      FOR EACH salesrep: 
        DISPLAY Salesrep.Sales-rep 
            WITH NO-LABELS 9 DOWN COLUMN 60 ROW 5. 
      END. 
   END. 
REPEAT WITH FRAME cust-frame: 
   PROMPT-FOR Customer.Cust-num. 
   FIND Customer USING Cust-num.  
   UPDATE Name Address Address2 City State Sales-rep. 
END. 

Use a trigger in place of the EDITING block to produce simpler, cleaner code. It would be easier to rewrite this code to be more event driven. First, replace the UPDATE statement with ENABLE, WAITFOR, and ASSIGN. You then might remove the REPEAT block and define a button that the user can select to move to the next Customer record. You might also replace the display of sales reps with a selection list or browse widget.

The following procedure uses an EDITING block to disallow normal data entry on a field and allow only a special key:

p-kystk.p
DEFINE FRAME cust-frame 
   Customer.Cust-num SKIP Customer.Name SKIP Customer.Address SKIP 
   Customer.Address2 SKIP Customer.City Customer.State SKIP 
   Customer.Sales-rep HELP "Use the space bar to scroll the values." 
   WITH SIDE-LABELS. 
REPEAT WITH FRAME cust-frame: 
   PROMPT-FOR Customer.Cust-num. 
   FIND Customer USING Cust-num. 
   UPDATE Name Address City State Sales-rep 
       EDITING: 
          READKEY. 
          IF FRAME-FIELD <> "Sales-rep" 
          THEN DO: 
             APPLY LASTKEY. 
          END. 
          ELSE DO: 
             IF LASTKEY = KEYCODE(" ") 
             THEN DO: 
                FIND NEXT Salesrep NO-ERROR. 
                IF NOT AVAILABLE Salesrep 
                THEN FIND FIRST Salesrep. 
                DISPLAY Salesrep.Sales-rep @ Customer.Sales-rep. 
             END. 
             ELSE IF LOOKUP(KEYFUNCTION(LASTKEY), 
                            "TAB,BACK-TAB,GO,END-ERROR") > 0 
                  THEN APPLY LASTKEY. 
                  ELSE BELL. 
          END. 
       END. 
END. 

Like p-kystka.p, this procedure uses an EDITING block on the UPDATE statement. In the EDITING block, it uses READKEY, LASTKEY, and FRAMEFIELD to obtain and analyze a keystroke. If the keystroke is not in the Salesrep field, it is processed normally. Within the Salesrep field, only the spacebar is treated specially and only the TAB, BACKTAB, GO, and ENDERROR key functions are treated normally. If the user types any other key within the field, the terminal bell sounds. When the user presses the spacebar in the Salesrep field, the value of that field and the Salesregion field change.

The following procedure uses triggers to accomplish the same thing:

p-kystk2.p
DEFINE FRAME cust-frame 
     Customer.Cust-num SKIP Customer.Name SKIP Customer.Address SKIP 
     Customer.Address2 SKIP Customer.City SKIP Customer.State SKIP  
     Customer.Sales-rep HELP "Use the space bar to scroll the values" 
     WITH SIDE-LABELS. 
ON " " OF Customer.Sales-rep 
   DO: 
     FIND NEXT Salesrep NO-LOCK NO-ERROR. 
     IF NOT AVAILABLE Salesrep 
     THEN FIND FIRST Salesrep NO-LOCK. 
     DISPLAY Salesrep.Sales-rep @ Customer.Sales-rep  
          WITH FRAME cust-frame. 
     RETURN NO-APPLY. 
   END. 
ON ANY-PRINTABLE OF Customer.Sales-rep 
   DO:  
     BELL. 
     RETURN NO-APPLY. 
   END. 
REPEAT WITH FRAME cust-frame: 
   PROMPT-FOR Customer.Cust-num. 
   FIND Customer USING Cust-num. 
   FIND Salesrep OF Customer NO-LOCK. 
   UPDATE Name Address Address2 City State Customer.Sales-rep.  
END. 

Note the use of RETURN NOAPPLY in both the ANYPRINTABLE and spacebar trigger. This is equivalent to omitting the APPLY LASTKEY statement in an EDITING block. Thus, the spacebar trigger brings the next Salesrep into view, without also inserting a space character in the field.

Note also that in p-kystk2.p the ANYPRINTABLE trigger rejects all keys that enter data characters other than a space. This works together with the spacebar trigger to allow only the spacebar and navigation keys (TAB, etc.) in the field.

Sometimes an EDITING block defines a special key that applies for all active fields:

p-kystk3.p
DEFINE FRAME cust-frame 
   Customer.Cust-num SKIP Customer.Name SKIP Customer.Address SKIP 
   Customer.Address2 SKIP Customer.City Customer.State SKIP 
   Customer.Sales-rep WITH SIDE-LABELS. 
REPEAT WITH FRAME cust-frame: 
   PROMPT-FOR Customer.Cust-num. 
   FIND Customer USING Cust-num. 
   MESSAGE "Press F6 to see the previous Customer.". 
   UPDATE Name Address Address2 City State Sales-rep  
       EDITING: 
          READKEY.  
          IF KEYLABEL(LASTKEY) = "F6" 
          THEN DO: 
             FIND PREV Customer NO-ERROR. 
             IF NOT AVAILABLE Customer 
             THEN FIND FIRST Customer. 
             DISPLAY Cust-num Name Address City State Sales-rep 
                WITH FRAME cust-frame. 
          END. 
          ELSE APPLY LASTKEY. 
       END. 
   HIDE MESSAGE. 
END. 

In p-kystk3.p, the EDITING block defines a special key, F6, that is available in all fields of the UPDATE statement. When the user presses this key, the previous Customer record displays.

The following procedure uses a trigger to achieve the same result:

p-kystk4.p
DEFINE FRAME cust-frame 
   Customer.Cust-num SKIP Customer.Name SKIP Customer.Address SKIP 
   Customer.Address2 SKIP Customer.City Customer.State SKIP 
   Customer.Sales-rep WITH SIDE-LABELS. 
ON F6 ANYWHERE 
  DO: 
     IF FRAME-FIELD = "Cust-num" 
     THEN RETURN NO-APPLY. 
     FIND PREV Customer NO-ERROR. 
     IF NOT AVAILABLE Customer 
     THEN FIND FIRST Customer. 
     DISPLAY Cust-num Name Address City State Sales-rep 
        WITH FRAME cust-frame. 
  END. 
REPEAT WITH FRAME cust-frame: 
   PROMPT-FOR Customer.Cust-num. 
   FIND Customer USING Cust-num. 
   MESSAGE "Press F6 to see the previous Customer.". 
   UPDATE Name Address Address2 City State Sales-rep. 
   HIDE MESSAGE. 
END. 

If you define a trigger to be active ANYWHERE, then it applies to all widgets. In p-kystk4.p, the F6 trigger executes whenever the user presses F6 while input is enabled. Within the trigger, the FRAME–FIELD function determines whether the t rigger executes from the UPDATE or PROMPT–FOR statement. If it is the PROMPT–FOR statement, then F6 is ignored; if it is the UPDATE statement, the previous Customer record displays.

NOTE: In a larger program, be careful of the scope of the ANYWHERE trigger. You are usually better off listing the specific widgets to which a trigger applies. For example, you could rewrite the ON statement in p-kystrk4.p as follows:

ON F6 OF Name, Address, Address2, City, State, Sales-rep 

If you take this approach, you can remove the code that checks whether FRAME–FIELD is Cust–num within the trigger.


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