Auto-complete in Natural Dialog (GUI)

I’m looking to see if anyone has also encountered, and found a work-around for auto-completing the value of a selection-box in a Natural Dialog.

I have the current functionality working:

  • Query the DB (get array of record objects) and populate a Selection Box with the record identifier (.name) at Dialog load time
  • Set-up the ‘Change’ Event handler to compare the entered text, slim down the items and display
  • Keep the current (new) value of the Selection-Box entered
  • If the Number of selections available = 1, choose it.

However, I run into this very frustrating issue:

  • When using PROCESS GUI ACTION DELETE-CHILDREN or PROCESS GUI ACTION CLEAR on the SELECTION-BOX, it also clears the value of the string and moves the cursor to the start of the box. Populating the string back into the box does not affect the cursor.
  • So when you try to type into the box, say ‘Start’ it would very smoothly come as ‘tratS’ since the cursor is reset to the start of the box each time.
  • Trying to use SET-FOCUS highlights the entire text, which isn’t very useful either :frowning:

Here is some code under the ‘Change’ event.

   /*[ DEFINE EVENTS FOR #SB-1
   VALUE #SB-1
      DECIDE ON FIRST *EVENT
         /*[ DEFINE EVENT CHANGE
         VALUE 'CHANGE'
            OPTIONS 2 CHANGE
            #sb-string := #sb-1.string
            if #sb-string <> ' ' and #sb-string <> #old-string
            #sb-1.suppress-change-event := 1
            #comp-array-size := 0
            reduce array #comp-name(*) to 0
            for #i = 1 to *occ(#comp-bs-list)
               examine #sb-string for ' ' giving length #len 
               #comp-string := #comp-bs-list.name(#i)
               #comp-string := substring(#comp-string, 1, #len)
               if #comp-string = #sb-string
                 add 1 to #comp-array-size
                 expand array #comp-name(*) to (1: #comp-array-size)
                 #comp-name(#comp-array-size) := #comp-bs-list.name(#i)
               end-if
            end-for

            process gui action DELETE-CHILDREN with #sb-1 giving #response
            if #comp-array-size = 1
              #sb-1.string := #comp-name(#comp-array-size)
            else
              #sb-1.string := #sb-string
            end-if
            #old-string := #sb-string            
            process GUI action ADD-ITEMS with #sb-1 4 #comp-name(*) giving #response
            /*Process GUI action SET-FOCUS with #sb-1 giving #response
            #sb-1.suppress-change-event := 0
            end-if
            OPTIONS 3
         /*] END-EVENT
      NONE
         PERFORM #DLG$HANDLER$DEFAULT
      END-DECIDE
   /*] END-EVENTS

Hey,

For those interested, I got back to this and tried a slightly different method which worked! And is better in every way.

It does the following.

  • Creates user-type box which with a ‘pop-up’ auto-complete dialogue.
  • When a match is made, it fills the field.
  1. Create an Input Field (#input) for the user to type in.
  2. Create a List Box (#list-box) just below it and set the ‘Enabled’ property to false, ‘Box dropped down’ property to True
  3. On Dialogue creation, get the array of items and populate them into the list-box using ADD-ITEMS with #array-value
  4. Set up the following ‘Events’ for the Input Field
  • Enter:
#list-box.visible := true
  • Leave:
#list-box.visible := false
  • Change:
#user-string := #input.string
            examine #user-string for ' ' giving length #len
            if #len = 0 then
              /* Reset the box
              process GUI action DELETE-CHILDREN with #sb-1 giving #response
              reduce array #list-box-array to 0
              #array-size := *occ(#object-array)
              expand array #list-box-array to (1: #array-size)
              for #i = 1 to #array-size
                 #array-value(#i) := #object-array.name(#i)
              end-for
              process GUI action ADD-ITEMS with #list-box #array-size #array-value(*) giving #response
              #list-box.visible := true
            end-if
            if #len > 0 then
             #list-box.visible := true
             #list-box.suppress-change-event := 1 /* just in case
             process GUI action DELETE-CHILDREN with #list-box giving #response
            reduce array #array-value(*) to 0
            reset #array-size
            #search-string := #user-string
            examine #search-string for ' ' giving length #len
            examine #search-string translate into lower
            for #i = 1 to *occ(#object-array)
               #compare-string := #object-array.name(#i)
               #compare-string := substring(#compare-string, 1, #len)
               examine #compare-string translate into lower
               if #compare-string = #search-string
                 add 1 to #array-size
                 expand array #array-value(*) to (1: #array-size)
                 #array-value(#array-size) := #object-array.name(#i)
               end-if
             end-for
             process GUI action ADD-ITEMS with #sb-1 #array-size #array-value(*) giving #response
             if #array-size = 1
              #input.suppress-change-event := 1
              #list-box.string := #array-value(1)
              #input.string := #array-value(1)
              process GUI action SET-FOCUS with #input giving #response
              #list-box.visible := false
              #input.suppress-change-event := 0
             else
              #list-box.string := #user-string
             end-if
             #list-box.suppress-change-event := 0
            end-if

Ops just re-read this. Should be a ‘Selection Box’ dialogue element rather than a ‘List Box’ for the above.