Does anyone know if an easy (and robust) way exists to make a search field in my A.S.Studio app that will search as I type, much like Finders search field?
I am trying to add this functionality to an application that pulls data from Filemaker, but does it as the user types the word he/she is searching for.
I’ve written the following code to do what you’re looking for. It will actively search the content of a text view for the string being typed into a text field, highlighting the string when found. I also included the framework for adding a “Find Next” feature, which searches sequentially for the search string until it reaches the end of the file, continuing back at the top when it reaches the end.
property theTextView : "" --> A persistent convenience reference to the text view
property theSearchField : "" --> A persistent convenience reference to the search field
(* * * * * * * * * * * * * Handlers * * * * * *)
on changed theObject --> Connected to the Search Field
if name of theObject is "SearchField" then
set {selectionStart, selectionEnd} to call method "selectedRange" of theTextView
findNext(selectionStart, selectionStart)
end if
end changed
on clicked theObject --> Connected to the "Find Next" button
if name of theObject is "FindNext" then
set {selectionStart, selectionEnd} to call method "selectedRange" of theTextView
findNext(selectionStart, selectionEnd)
end if
end clicked
on launched theObject --> Connected to file's owner
set theSearchField to (text field "SearchField" of window "Window")
set theTextView to (text view "Text" of scroll view "Scroll" of window "Window")
end launched
(* * * * * * * * * * * * * Subroutines * * * * * *)
(* Finds the next occurrence of the query in the text *)
to findNext(selectionStart, selectionEnd)
set tmpQuery to (content of theSearchField) as string
set tmpText to (content of theTextView) as string
if (tmpQuery is not "") and (tmpText is not "") then
(* See if there is already a selection *)
if (selectionEnd = (length of tmpText)) then set {selectionStart, selectionEnd} to {0, 0}
(* Define the text string we will be searching in *)
if (selectionEnd + 1) < (length of tmpText) then
set tmpText to (characters (selectionEnd + 1) through -1 of tmpText) as string
else
set tmpText to (character -1 of tmpText) as string
end if
(* See if the text betweeen the selection and the end of the text contains the query *)
set {retryFromTop, tmpRange} to find_In_Text(tmpQuery, tmpText)
(* Retry the search from the top of the text if the query was not found after the selection *)
if retryFromTop then
set tmpText to (content of theTextView) as string
set {selectionStart, selectionEnd} to {0, 0}
set {retryFromTop, tmpRange} to find_In_Text(tmpQuery, tmpText)
end if
(* Highlight the match if another one was found *)
if retryFromTop is false then
set {offsetStart, offsetEnd} to tmpRange
set offsetStart to (offsetStart + selectionEnd)
set offsetEnd to (offsetEnd + selectionEnd)
tell theTextView to call method "setSelectedRange:" of it with parameters {{offsetStart, offsetEnd}}
end if
else
tell theTextView to call method "setSelectedRange:" of it with parameters {{0, 0}}
end if
end findNext
(* Locates the query in the text string and returns it's character range *)
to find_In_Text(tmpQuery, tmpText)
if (tmpText contains tmpQuery) then
set offsetStart to ((offset of tmpQuery in tmpText) - 1)
set offsetEnd to (offsetStart + (length of tmpQuery))
return {false, {offsetStart, offsetEnd}}
else
return {true, {0, 0}}
end if
end find_In_Text