by Cal Locklin (CALocklin@aol.com)
Cal shows us a way to create a 'locate text' button for forms containing
child browse tables which will
|
PROBLEM: The A5 'Locate' command can create confusion for users in certain circumstances. First, it will not check the current record. So, even though my original "Locate" button changed to the first record before starting the 'Locate' command, the first record was not searched. Second, when multiple child records (in sets) are involved, it will appear to keep 'locating' the same parent record. This happens because the search looks for the next record and each child record represents a new record - including all the data in the parent record. Since most users (vs. developers) don't know what's happening, they think something is wrong.
SOLUTION: A Locate button
containing the Xbasic script below solves the problem by checking the first
record then making sure each subsequent 'Locate' operation starts from the last
child record of the current parent. As added bonuses, it:
- allows the user to select which fields to search.
(Change the field names to match your own.)
- provides the user a more intuitive way to continue a search.
When the user first clicks the Locate
button, he is prompted to type the search text:

Next is a prompt for which field(s) to search. Of course, your script
will need to be modified to include your own field names. (This option
can be left out and the choice of which field(s) to search would be up to the
programmer but I left it in as an example for those who want to use it.)

When the user selects which field to search, the search is completed and the
user is left in the 'located' record.
Note: On the line with "All" I added reference to the
various tables in my set. This is used to remind the user that all fields
in all tables will be searched - not just the ones shown on the screen.
Elsewhere in my application, I have included a Help file with more description
of how the Locate button works.
When the user has already run a 'Locate' operation during the current session, the first prompt will be different. The first prompt will be for a 'search type'. This allows a choice between a "New" search and "Locate Next". The search text from the last search is included in the "Locate Next" line as a reminder.

If "Locate Next" is chosen, the locate operation runs immediately. If "New" is chosen, the program goes through the "TEXT TO SEARCH FOR" and "FIELDS TO SEARCH" prompts shown above.
To continue a previous search, the user can simply press the Enter button twice - once to active the Locate button and again to activate the search. (This assumes, of course, that the user has not moved the cursor from the Locate button and that the programmer leaves "Locate Next" as the default selection for "SEARCH TYPE".)
If the search is run and no more records are found, the user is
notified:

(Did you catch the title in that last pop up? In the script for my own
application, I actually print the name of the current index to avoid confusion
about which records were searched. That adds a bit more complexity and I
didn't want to make this presentation any more difficult to explain.
Anyone who wants a copy of the script which includes this feature, e-mail
me at CALocklin@aol.com.)
The comments in the script provide additional information about what the
program does and how it works.
AND NOW THE SCRIPT:
DIM GLOBAL
global_search_text as c
DIM GLOBAL global_search_field as c
'---------------------------------------------------------------------------------
' MAKE SURE THE USER ISN'T STILL ENTERING/MODIFYING THE CURRENT RECORD.
'---------------------------------------------------------------------------------
stbl=table.current()
IF stbl.mode_get() > 0
ui_msg_box( "ERROR", "In data entry mode.
Please save record before running\
the LOCATE operation.", 48)
END
END IF
'---------------------------------------------------------------------------------
' IF DESIRED, THIS SECTION CAN BE USED TO INFORM THE USER HOW THE BUTTON
WORKS.
'---------------------------------------------------------------------------------
'response=ui_msg_box( "INFORMATION", \
'"This command will find the FIRST occurrence of the text you enter."
+chr(013)+ \
'"- To find additional occurrences, simply press the ENTER key
twice." +chr(013)+ \
'"- Repeat this sequence until you see the message box 'No more
occurrences found'.", \
'UI_INFORMATION_SYMBOL+UI_OK_CANCEL )
'IF response=ui_cancel_selected
' END
'END IF
'---------------------------------------------------------------------------------
' IF NO global_search_text EXISTS, THIS ROUTINE HAS NOT BEEN RUN BEFORE IN
' THIS SESSION SO IT MUST BE A NEW SEARCH.
' OTHERWISE, FIND OUT WHETHER TO REPEAT THE PREVIOUS SEARCH OR START A NEW
ONE.
'---------------------------------------------------------------------------------
IF global_search_text=""
search_type="New"
ELSE
search_type=ui_get_list( "SEARCH TYPE", 1, "Locate
Next '" + global_search_text + "'", "New" )
IF search_type=""
END
END IF
END IF
'---------------------------------------------------------------------------------
' IF IT IS A NEW SEARCH, FIND OUT WHAT TEXT TO SEARCH FOR AND WHICH
FIELD(S)
' TO SEARCH. THEN, SEARCH THE FIRST RECORD.
' *NOTE*: GOING TO THE FIRST RECORD AND DOING A .fetch_loc_next WILL
NOT
' SEARCH THE FIRST
RECORD.
'---------------------------------------------------------------------------------
IF search_type="New"
global_search_text=ui_get_text( "TEXT TO SEARCH FOR",
"Enter search text - caps not\
important.", global_search_text )
IF global_search_text=""
END
END IF
global_search_field=ui_get_list( "FIELD TO SEARCH", 1,
"Status", "Description",\
"All - Task, Project, Actions" )
IF global_search_field=""
END
ELSE
IF global_search_field="All - Task, Project,
Actions"
global_search_field=""
END IF
'---------------------------------------------------------------------------
' THIS AREA CAN BE MODIFIED TO ALLOW YOU TO ASK FOR A
GENERIC
' FIELD NAME THAT THE USER UNDERSTANDS AND THEN
CONVERT TO
' THE REAL FIELD NAME.
' ex: IF global_search_field="Status"
'
global_search_field="Stat_1"
' END IF
' THIS COULD EVEN BE EXPANDED TO WORK WITH MULTIPLE
FORMS BY
' CHECKING THE FORM NAME. CONTACT CALocklin@aol.com
FOR MORE INFO.
'---------------------------------------------------------------------------
END IF
'------------------------------------------------------------------------------
' CHECK THE FIRST RECORD BY GOING TO THE SECOND RECORD THEN
SEARCHING BACKWARD.
'------------------------------------------------------------------------------
stbl.fetch_first()
stbl.fetch_next()
found=stbl.fetch_loc_prev( global_search_text, global_search_field
)
IF found
parentform.resynch()
END
ELSE
'---------------------------------------------------------------------------
' IF "fetch_loc_prev" DOESN'T FIND IT, THE
POINTER STAYS IN THE SECOND
' RECORD. THIS LINE TAKES YOU BACK TO THE FIRST RECORD
SO THE SEARCH CAN
' CONTINUE LATER.
'---------------------------------------------------------------------------
stbl.fetch_first()
END IF
ELSE '--- search_type *NOT* "New"
current_rec=table.current().recno()
'------------------------------------------------------------------------------
' FIND NEXT *PARENT* RECORD (next RECORD could be just a new child
record.)
' USING A "1" IN THE .fetch_next() FETCHES ONLY THE
PARENT TABLE.
'------------------------------------------------------------------------------
table.current().fetch_next(1)
'------------------------------------------------------------------------------
' IF THE 'NEXT' PARENT RECORD IS THE SAME AS THE CURRENT RECORD,
THEN WE WERE
' ALREADY IN THE LAST RECORD. OBVIOUSLY NOTHING ELSE TO SEARCH.
' OTHERWISE, BACK UP ONE RECORD TO THE LAST CHILD RECORD OF THE
'CURRENT'
' RECORD. BY STARTING THE NEXT SEARCH AT THE LAST CHILD RECORD OF
THE CURRENT
' PARENT RECORD, WE WILL NOT BE CHECKING THE CURRENT RECORD
AGAIN.
'------------------------------------------------------------------------------
next_rec=table.current().recno()
IF current_rec=next_rec
ui_msg_box( "DONE", "No more
occurrences found.")
END
ELSE
table.current().fetch_prev()
END IF
END IF
'---------------------------------------------------------------------------------
' THIS IS THE NORMAL 'LOCATE' ROUTINE USED TO SEARCH EVERYTHING BUT THE
FIRST
' RECORD. ALSO, IT IS NOT USED IF THE TEXT WAS ALREADY FOUND IN THE *LAST*
RECORD.
'---------------------------------------------------------------------------------
found=stbl.fetch_loc_next( global_search_text, global_search_field )
'---------------------------------------------------------------------------------
' WARN THE USER IF NOTHING WAS FOUND.
'---------------------------------------------------------------------------------
IF .not.found
ui_msg_box( "DONE", "No more occurrences
found.")
ELSE
parentform.resynch()
END IF
END
12/4/99
Don't forget, we need your feedback to make this site better!