Try OpenEdge Now
skip to main content
Programming Interfaces
Input/Output Processes : Handling User Input : Monitoring keystrokes during data entry : Using editing blocks and user interface triggers
 
Using editing blocks and user interface triggers
Note: EDITING blocks are a deprecated feature. Prior to event-driven programming, ChUI procedural applications used EDITING blocks. EDITING blocks are not appropriate for event-driven, multi-tier, or Service-Oriented applications. Use the WAIT-FOR statement to replace EDITING blocks.
The i-kystka.p procedure uses an EDITING block on the UPDATE statement to enable a special key while allowing normal data entry.
i-kystka.p
DEFINE FRAME cust-frame
  Customer.CustNum SKIP Customer.Name SKIP Customer.Address SKIP
  Customer.Address2 SKIP Customer.City Customer.State SKIP
  Customer.SalesRep HELP "To see a list of values, press F6."
  WITH DOWN SIDE-LABELS.

REPEAT WITH FRAME cust-frame:
  PROMPT-FOR Customer.CustNum.
  FIND Customer USING Customer.CustNum.
  UPDATE Customer.Name Customer.Address Customer.Address2 Customer.City
    Customer.State Customer.SalesRep EDITING:
    READKEY.
    IF FRAME-FIELD = "salesrep" AND LASTKEY = KEYCODE("F6") THEN DO:
      FOR EACH SalesRep NO-LOCK:
        DISPLAY SalesRep.SalesRep
          WITH NO-LABELS 9 DOWN COLUMN 60 ROW 5.
      END.
    END.
    ELSE
      APPLY LASTKEY.
  END. /* UPDATE */
END. /* REPEAT */
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 FRAME–FIELD 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 the AVM to handle the keystroke normally.
The i-kystkb.p procedure uses a user interface trigger in place of the EDITING block to achieve the same functionality.
i-kystkb.p
DEFINE FRAME cust-frame
  Customer.CustNum SKIP Customer.Name SKIP Customer.Address SKIP
  Customer.Address2 SKIP Customer.City Customer.State SKIP
  Customer.SalesRep HELP "To see a list of values, press F6."
  WITH DOWN SIDE-LABELS.

ON F6 OF Customer.SalesRep DO:
  FOR EACH SalesRep NO-LOCK:
    DISPLAY SalesRep.SalesRep
      WITH NO-LABELS 9 DOWN COLUMN 60 ROW 5.
  END.
END.

REPEAT WITH FRAME cust-frame:
  PROMPT-FOR Customer.CustNum.
  FIND Customer EXCLUSIVE-LOCK USING Customer.CustNum.
  UPDATE Customer.Name Customer.Address Customer.Address2 Customer.City
    Customer.State Customer.SalesRep.
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, WAIT–FOR, 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 i-kystkbk.p procedure uses an EDITING block to disallow normal data entry on a field and allow only a special key.
i-kystk.p
DEFINE FRAME cust-frame
  Customer.CustNum SKIP Customer.Name SKIP Customer.Address SKIP
  Customer.Address2 SKIP Customer.City Customer.State SKIP
  Customer.SalesRep HELP "Use the space bar to scroll the values."
  WITH SIDE-LABELS.

REPEAT WITH FRAME cust-frame:
  PROMPT-FOR Customer.Custnum.
  FIND Customer EXCLUSIVE-LOCK USING Customer.Custnum.
  UPDATE Customer.Name Customer.Address Customer.City Customer.State
    Customer.SalesRep EDITING:
    READKEY.
    IF FRAME-FIELD <> "salesrep" THEN
      APPLY LASTKEY.
    ELSE DO:
      IF LASTKEY = KEYCODE(" ") THEN DO:
        FIND NEXT SalesRep NO-LOCK NO-ERROR.
        IF NOT AVAILABLE SalesRep THEN
          FIND FIRST SalesRep NO-LOCK.
        DISPLAY SalesRep.SalesRep @ Customer.SalesRep.
      END.
      ELSE IF LOOKUP(KEYFUNCTION(LASTKEY),
        "TAB,BACK-TAB,GO,END-ERROR") > 0 THEN APPLY LASTKEY.
      ELSE BELL.
    END.
  END. /* UPDATE */
END. /* REPEAT */
Like i-kystka.p, this procedure uses an EDITING block on the UPDATE statement. In the EDITING block, it uses READKEY, LASTKEY, and FRAME–FIELD to obtain and analyze a keystroke. If the keystroke is not in the Salesrep field, it is processed normally. Within the SaleRep field, only the spacebar is treated specially and only the TAB, BACK–TAB, GO, and END–ERROR 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 i-kystk2.p procedure uses triggers to accomplish the same thing.
i-kystk2.p
DEFINE FRAME cust-frame
  Customer.Custnum SKIP Customer.Name SKIP Customer.Address SKIP
  Customer.Address2 SKIP Customer.City SKIP Customer.State SKIP
  Customer.SalesRep HELP "Use the space bar to scroll the values"
  WITH SIDE-LABELS.

ON " " OF Customer.SalesRep DO:
  FIND NEXT SalesRep NO-LOCK NO-ERROR.
  IF NOT AVAILABLE SalesRep THEN
    FIND FIRST SalesRep NO-LOCK.
  DISPLAY SalesRep.SalesRep @ Customer.SalesRep WITH FRAME cust-frame.
  RETURN NO-APPLY.
END.

ON ANY-PRINTABLE OF Customer.SalesRep DO:
  BELL.
  RETURN NO-APPLY.
END.

REPEAT WITH FRAME cust-frame:
  PROMPT-FOR Customer.CustNum.
  FIND Customer EXCLUSIVE-LOCK USING Customer.CustNum.
  FIND SalesRep OF Customer NO-LOCK.
  UPDATE Customer.Name Customer.Address Customer.Address2 Customer.City
    Customer.State Customer.SalesRep.
END.
Note the use of RETURN NO–APPLY in both the ANY–PRINTABLE 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 i-kystk2.p the ANY–PRINTABLE 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, as shown in the i-kystk3.p procedure.
i-kystk3.p
DEFINE FRAME cust-frame
  Customer.CustNum SKIP Customer.Name SKIP Customer.Address SKIP
  Customer.Address2 SKIP Customer.City Customer.State SKIP
  Customer.SalesRep WITH SIDE-LABELS.

REPEAT WITH FRAME cust-frame:
  PROMPT-FOR Customer.CustNum.
  FIND Customer EXCLUSIVE-LOCK USING Customer.CustNum.
  MESSAGE "Press F6 to see the previous Customer.".
  UPDATE Customer.Name Customer.Address Customer.Address2 Customer.City
    Customer.State Customer.SalesRep EDITING:
    READKEY.
    IF KEYLABEL(LASTKEY) = "F6" THEN DO:
      FIND PREV Customer NO-LOCK NO-ERROR.
      IF NOT AVAILABLE Customer THEN
        FIND FIRST Customer NO-LOCK.
      DISPLAY Customer.CustNum Customer.Name Customer.Address Customer.City
        Customer.State Customer.SalesRep
        WITH FRAME cust-frame.
    END.
    ELSE APPLY LASTKEY.
  END.
  HIDE MESSAGE.
END.
In i-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 i-kystk4.p procedure uses a trigger to achieve the same result.
i-kystk4.p
DEFINE FRAME cust-frame
  Customer.CustCum SKIP Customer.Name SKIP Customer.Address SKIP
  Customer.Address2 SKIP Customer.City Customer.State SKIP
  Customer.SalesRep WITH SIDE-LABELS.

ON F6 ANYWHERE DO:
  IF FRAME-FIELD = "custnum" THEN
    RETURN NO-APPLY.

  FIND PREV Customer NO-ERROR.
  IF NOT AVAILABLE Customer THEN
    FIND FIRST Customer.

  DISPLAY Customer.CustNum Customer.Name Customer.Address Customer.City
    Customer.State Customer.Salesep
    WITH FRAME cust-frame.
END. /* ON F6 */

REPEAT WITH FRAME cust-frame:
  PROMPT-FOR Customer.CustNum.
  FIND Customer EXCLUSIVE-LOCK USING Customer.CustNum.
  MESSAGE "Press F6 to see the previous Customer.".
  UPDATE Customer.Name Customer.Address Customer.Address2 Customer.City
    Customer.State Customer.SalesRep.
  HIDE MESSAGE.
END.
If you define a trigger to be active ANYWHERE, then it applies to all widgets. In i-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.
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 i-kystrk4.p as follows:
ON F6 OF Name, Address, Address2, City, State, SalesRep
If you take this approach, you can remove the code that checks whether FRAME–FIELD is CustNum within the trigger.