vba or api hilite partial text in a textbox and place the text cursor (not the mouse) after the hilited text

Posted on 2009-12-28
Last Modified: 2012-05-08
Dear Experts,

I am taking a multi-line textbox in access (I cannot add a rich text box control to the form, access says it cannot add it, so this is a regular textbox) and when the user types in something on the first line and then types in something on the second line that matches the first I want it to automatically fill in the first word (the one from line1) on the second line, hilite it in case the user is trying to type something else, and then put the cursor position for the textbox right after the hilited text.

So, if user types this on the first line:
And then on the second line types
I want it to automatically fill in SMITH on the second line, hilite SMITH and then put the caret right next to it on the right (right now it is putting it on the left)

The simple answer would be to simply set the selstart to the length of the line, but doing so unhilites the text, I will post my partially working code below in the code section..

Note: I am willing to use windows API calls if that's what it takes to do this.

Thanks! ~Michael
Private Sub Seller_KeyUp(KeyCode As Integer, Shift As Integer)

    Dim myText$, buyerText$, currKey$

    currKey = Chr(KeyCode): myText = UCase(Nz(Me.Seller.text)): buyerText = UCase(Nz(Me.Buyer))

    If InStr("ABCDEFGHIJKLMNOPQRSTUVWXYZ ", UCase(currKey)) > 0 Then

        If InStr(myText, vbCr) > 0 Then

            Dim line2$, line1$, line1_word1$, line2_word1$, newText$, newPos As Integer

            line1 = firstLine(myText)

            line1_word1 = firstWord(myText)

            line2 = secondLine(myText)

            line2_word1 = firstWord(line2)

            If InStr(line2, " ") > 0 Then Exit Sub 'must be still typing the first word of the second line

            If Len(line2_word1) < 2 Then Exit Sub

            If line2_word1 = Left(line1_word1, Len(line2_word1)) Then

                'words are matching, insert word and hilite just that word

                newText = line1 & vbCrLf

                newPos = Len(newText) + 1

                newText = newText & line1_word1 & " "

                Me.Seller = newText

                Me.Seller.SelStart = newPos

                Me.Seller.SelLength = Len(line1_word1) + 1	'now the cursor is on the left of the hilited text (selstart) which is wrong

            End If

       end if

end sub

'Other supporting functions

Public Function firstLine(ByVal someStr$) As String

    firstLine = myTrim(someStr, vbCrLf)

    If InStr(firstLine, vbCrLf) = 0 Then Exit Function

    firstLine = Left(firstLine, InStr(firstLine, vbCrLf) - 1)

End Function

Public Function secondLine(ByVal someStr$)

    'returns "" if there is no 2nd line

    Dim linePos As Integer

    linePos = InStr(someStr, vbCrLf)

    If linePos = 0 Then Exit Function

    secondLine = Mid(someStr, linePos + 2)

    linePos = InStr(secondLine, vbCrLf)

    If linePos > 0 Then secondLine = Mid(secondLine, 1, linePos - 1)

End Function

Public Function firstWord(ByVal someStr$) As String

    firstWord = Trim(someStr)

    If InStr(firstWord, " ") = 0 Then Exit Function

    firstWord = Left(firstWord, InStr(firstWord, " ") - 1)

End Function

Open in new window

Question by:JeffreyDurham
    LVL 25

    Accepted Solution

    OK, my question is why do you care where the caret is?  It seems you would want to be storing each line of text in an array or something after the user presses enter (which you could check for in the keypress or keyup event) that point add to the array or string collection.
    Then as they type, trap each char and remember what they have typed so far on that line by storing it in a variable....trap it on keydown, keypress or keyup, depending on how you want it to behave.  compare to the array. If it meets a condition there, replace that text with whatever it matches, keep doing this until a key comes in that makes it a unique word. At that point, deselect it all, add the string you've been tracking + the char they just pressed and set selstart to the end of that line.

    Isn't this what you are after?
    LVL 25

    Expert Comment

    If not, here is an article on getting and setting the textbox caret from

    It uses SendMessage,GetCaretPos, and SetCaretPos API calls - note you will need the pre version of DECLARES for use in VBA
    LVL 38

    Expert Comment

    this link uses an html tag in a rich texbox....see if it helps for what you want it to do:
    LVL 31

    Expert Comment

    I would suggest a completely different approach.  Make a table to store the values that are now typed into lines of the multi-line textbox, and display it in a datasheet subform.  This is better from the point of view of normalization, and much easier to work with besides.

    Author Comment

    No worries Jim Dettman, my first name is Jeffrey, and my second name is Michael. So for work, money, taxes, etc, I go by Jeffrey, but I otherwise go by Michael, which is why I will end comments or letters or whatever with Michael. But yeah, it's just me.

    Actually I like your idea for how to track it using an array or whatnot. The only reason I wanted the caret at the end is if the user liked the word and kept typing, I wanted them to be able to hit the arrow key once to get over and then keep typing, or I was debating trapping the space, and if the word is good just keep going. But basically, the reason was the cursor was way to the left of the word and that was awkward for entering data and stuff. Umm, lemme toy with your idea and if that doesn't go I'll do the API. Thanks!

    Author Comment

    For this field I really only need to deal with two lines of text, so I don't think it's really necessary to make a table to hold the data. I think just holding the text in memory wouldn't be a big deal since it's so little, and would probably be faster.
    LVL 25

    Expert Comment

    Well yeah... You could still trap the tab key, deselect, move caret to the end.  

    Author Closing Comment

    Thank you SStory!

    Yep, keeping it in memory and altering it to fit is an excellent approach. Thanks for the good idea! Also, thanks for the api info too, now I know everything I wanted to know!

    LVL 25

    Expert Comment

    Hey you are welcome.

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Highfive Gives IT Their Time Back

    Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

    I originally created this report in Crystal Reports 2008 where there is an option to underlay sections. I initially came across the problem in Access Reports where I was unable to run my border lines down through the entire page as I was using the P…
    I see at least one EE question a week that pertains to using temporary tables in MS Access.  But surprisingly, I was unable to find a single article devoted solely to this topic. I don’t intend to describe all of the uses of temporary tables in t…
    Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…
    With Microsoft Access, learn how to specify relationships between tables and set various options on the relationship. Add the tables: Create the relationship: Decide if you’re going to set referential integrity: Decide if you want cascade upda…

    779 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    12 Experts available now in Live!

    Get 1:1 Help Now