Solved

Set Insertion point in a textbox with a selection.

Posted on 1998-12-01
18
364 Views
Last Modified: 2012-05-04
Has anyone ever noticed that when you use the SelStart and SelLength properties of a textbox, the caret (insertion point) is always to the right of the selection?  It is possible to manually put the insertion point at the beginning of the selection.  For example, hold the shift key down and hit the left arrow a couple times.  But I want to do this programatically.  Have all the text selected with the caret at the beginning, not the end.  Now I'm not looking for a hack answer like use SendKeys or the like.  I could make it work with a hack myself.  I want to know how it's really done...  Using the API, sending message(s) or perhaps I'm just totally missing something with the control's properties.  It's seems that a simple way the control COULD give the functionality would be to set the SelStart and then have a negative SelLength.  Unfortunately, SelLength will not take a negative number.  hmmm...
0
Comment
Question by:Chamberlain
  • 5
  • 5
  • 3
  • +4
18 Comments
 
LVL 1

Expert Comment

by:muffinthedog
ID: 1447648
Can't think of any message you could send to a "Thunder TextBox" that will give you the results you seek. You could subclass the control and go from there. Think you may have to hack this one out with send keys or sendmessage WM_KEYDOWN/UP or something...

0
 
LVL 2

Expert Comment

by:AllenC_Jr
ID: 1447649
Ok this one is a simple one...

Rather than setting the sel start to the start of the text do the opposite...

If a text box had this text in it

'This is a test'

and I set the SelStart to 0 and SelEnd to 3 the letters 'Thi' would be selected and the caret would be on the right side of the text.
But if I set the SelEnd to 0 and The SelStart to 3 then The characters selected would still be 'Thi' and the caret would be on the left side of the selected text.

The way I found this out... I guessed...
0
 
LVL 1

Author Comment

by:Chamberlain
ID: 1447650
The TextBox DOES NOT have a SelEnd property.

C'mon..  you just wasted my time having me launch explorer and sign in to check out this bogus answer.  Plus, you locked my question all night.  If you're going to be answering as an expert, then you should know the subject material.  

0
 

Expert Comment

by:Geer
ID: 1447651
c'mon AllenC, it would've taken you 2 minutes to look this up in VB.  This isn't a place to be guessing - people are trying to do real work here.   I don't want to start a flame war or anything, but GEEZ!
0
 
LVL 2

Expert Comment

by:AllenC_Jr
ID: 1447652
Oh, Geeze I am sorry!


Public Sub SelectText(TextBox As TextBox, SelStart, SelEnd)
If SelStart > SelEnd Then
txtBox.SetFocus
txtBox.SelStart = SelStart
SendKeys "+{Left " & (SelStart - SelEnd) + 1 & "}"
Else
txtBox.SetFocus
txtBox.SelStart = SelStart
SendKeys "+{Right " & (SelEnd - SelStart) + 1 & "}"
End If
End Sub

Example

SelectText txtBox1, 4, 1'Selects the first four letters with the carret on the left side...


It uses send keys...

Sorry about that.
0
 
LVL 2

Expert Comment

by:AllenC_Jr
ID: 1447653
Oh, and the example took exactly 2 min to create... :-þ

Here is code for fun...


Here is how to programatically split a file into pieces...

WARNING!
This code is marked as Advanced...
--------------------------------------------------------
Module: modSplit
Author: Allen Copeland
E-Mail: Allenc_jr@hotmail.com
Level : Advanced
Found _
Where : www.VB-Helper.com
Notice: If any code is missing get the full version here at
http://www.vb-helper.com/howto.htm
--------------------------------------------------------

Option Explicit
Type FileSection
    Bytes() As Byte
    FileLen As Long
End Type
Type SectionedFile
    Files() As FileSection
    NumberOfFiles As Long
End Type
Type FileInfo
    OrigProjSize As Long
    OrigFileName As String
    FileSectionPath As String
    FileCount As Integer
    FileStartNum As Long
End Type

Public Function SplitFile(SplitFileName As String, _
BeginningNumber As Long, ReturnErrorDes As String, Optional Split As Long = _
1439865, Optional OutTemplateName As String) As Boolean
    Dim SaveName As String
    SplitFile = True 'Assume Success
    On Error GoTo CleanUp
    Dim CurrentFile As SectionedFile, m_lngNumFil As Long, m_lngLoop As Long, FilesLen As Long
    FilesLen = FileLen(SplitFileName)
    If FilesLen <= Split + 1 Then
    SplitFile = False 'If the File _
    Name is Smaller than the Split Ratio then _
    The Function Doesnt Need Called So it Fails.
    ReturnErrorDes = "File Is Too Small"
    Exit Function
    End If
    Open SplitFileName For Binary As #1 'I Use #1 as _
    Default Because I Normally Only Open one _
    File At a Time. If needed it can be changed.
        If (FilesLen \ Split) >= _
        FilesLen / Split Or (FilesLen \ Split) _
        = FilesLen / Split Then
            m_lngNumFil = (FilesLen _
            \ Split)  ' If VB heightened(or if they _
            were equal) the length of the file _
            divided by the total Split ratio then _
            nothing needs To Do anything.
        ElseIf (FilesLen \ Split) <= _
        FilesLen / Split Then
            m_lngNumFil = (FilesLen \ _
            Split) + 1 ' If VB Lowered The _
            Length Of the File Divided by the Total _
            Split Ratio then it Will Need To Correct _
            it.
        End If
        ReDim CurrentFile.Files(1 To m_lngNumFil)
        For m_lngLoop = 1 To m_lngNumFil - 1
            ReDim CurrentFile.Files(m_lngLoop) _
                .Bytes(1 To Split) 'Re-Define(Re _
                Dimention) the Number Of Bytes Per _
                File
            CurrentFile.Files(m_lngLoop) _
                .FileLen = UBound(CurrentFile.Files _
                (m_lngLoop).Bytes) 'Just For Reference
        Next
        For m_lngLoop = 1 To m_lngNumFil
            Get #1, , CurrentFile.Files(m_lngLoop) _
            .Bytes
        Next
        ReDim CurrentFile.Files(m_lngNumFil) _
            .Bytes(1 To FilesLen - ((m_lngNumFil _
            - 1) * Split)) 'ReDefine the Number of _
            bytes for the last file since in many cases _
            it will not be at the Split ratio.
        CurrentFile.NumberOfFiles = m_lngNumFil
        Get #1, , CurrentFile.Files(m_lngNumFil) _
            .Bytes
        CurrentFile.Files(m_lngNumFil) _
            .FileLen = UBound(CurrentFile.Files _
            (m_lngNumFil).Bytes)
    Close #1 'Close File(1)
    For m_lngLoop = 1 To CurrentFile.NumberOfFiles _
    'Save What We Have Done Into Seperate Files
        SaveName = FilePath(OutTemplateName) & ReturnFileName(SplitFileName) & "." & Format(BeginningNumber - 1 + m_lngLoop, _
        "00#")
        Open SaveName For Binary As #1
            Put #1, 1, CurrentFile.Files(m_lngLoop)
        Close #1
    Next
    Dim FileInfoFile As FileInfo
    FileInfoFile.FileCount = m_lngNumFil
    FileInfoFile.OrigFileName = SplitFileName
    FileInfoFile.FileSectionPath = FilePath(SaveName)
    FileInfoFile.OrigProjSize = FileLen(SplitFileName)
    FileInfoFile.FileStartNum = BeginningNumber
    If OutTemplateName = "" Then
    SaveName = SplitFileName & ".tpl"
    Else
    SaveName = OutTemplateName
    End If
    On Error Resume Next
    Open SaveName For Binary As #1
        If Err <> 0 Then ReturnErrorDes = Err.Description _
            : SplitFile = False: Exit Function
        Put #1, , FileInfoFile
    Close #1
    Exit Function
CleanUp:
    ReturnErrorDes = Err.Description
    SplitFile = False
End Function

Public Function ReassembleFile(TemplateFileName As String, _
    Optional UseOldFilename As Boolean = True, Optional _
    OutPutName = "C:\Filname.Extention") As Boolean
    Dim FileInfo As FileInfo, OutName As String, File As _
    SectionedFile, m_lngLoop As Long, OpenName
    ReassembleFile = True 'Assume Success
    If Len(TemplateFileName) = 0 Then ReassembleFile = False: Exit Function
    Open TemplateFileName For Binary As #1
        Get #1, , FileInfo 'Get Information on the _
        Previously Saved File(s)
    Close #1
    If UseOldFilename Then
        OutName = FileInfo.OrigFileName
    Else
        OutName = OutPutName
    End If
    ReDim File.Files(1 To FileInfo.FileCount)
    For m_lngLoop = 1 To FileInfo.FileCount
        OpenName = FileInfo.FileSectionPath & ReturnExtention(FileInfo.OrigFileName, False, "\") & "." & _
        Format((FileInfo.FileStartNum - 1 + _
        m_lngLoop), "00#")
        Open OpenName For Binary As #1
            Get #1, 1, File.Files(m_lngLoop)
        Close #1
    Next
    Open OutName For Binary As #1
        For m_lngLoop = 1 To FileInfo.FileCount
            Put #1, , File.Files(m_lngLoop).Bytes
        Next
    Close #1
End Function

Public Function ReturnFileName(Text As String)
    Dim XText As String, DLines() As String
    XText = Text
    If Not Right(XText, 1) = "\" Then XText = XText & "\"
    SplitDirName CStr(XText), DLines()
    ReturnFileName = DLines(UBound(DLines))
End Function

Public Function FilePath(FileName As String) As String
    Dim XText As String, DFileName As String, m_lngLoop As Long, DLines() As String
    XText = FileName
    If Not Right(XText, 1) = "\" Then XText = XText & "\"
    SplitDirName CStr(XText), DLines()
    For m_lngLoop = 1 To UBound(DLines) - 1
        DFileName = DFileName & DLines(m_lngLoop) & "\"
    Next
    FilePath = DFileName
End Function
Sub SplitDirName(DirName As String, Lines() As String)
'SplitDirName
'Created By Allen
    If DirName = "" Then Exit Sub
    Dim Text As String, CurNum As Long, TotalNum As Long, CurPos As Long
    Text = DirName
    CurNum = 1
    CurPos = 1
    TotalNum = GetCount(Text, "\")
    ReDim Lines(1 To TotalNum)
    Do Until CurNum = TotalNum + 1
        Lines(CurNum) = Mid(Text, 1, InStr(CurPos, Text, "\") - 1)
        Text = Mid(Text, Len(Lines(CurNum)) + 2)
        CurNum = CurNum + 1
    Loop
End Sub

Public Function GetCount(Text As String, Search As String)
    Dim CCnt As Long, m_lngLoop As Long
    For m_lngLoop = 1 To Len(Text)
        If Mid(Text, m_lngLoop, Len(Search)) = Search Then
            CCnt = CCnt + 1
        End If
    Next
    GetCount = CCnt
End Function

--------------------------------------------------------
Note: If you have any comments or questions, E-Mail Me @ allenc_jr@hotmail.com
0
 
LVL 2

Expert Comment

by:AllenC_Jr
ID: 1447654
Oh, and the example took exactly 2 min to create... :-þ

Here is code for fun...


Here is how to programatically split a file into pieces...

WARNING!
This code is marked as Advanced...
--------------------------------------------------------
Module: modSplit
Author: Allen Copeland
E-Mail: Allenc_jr@hotmail.com
Level : Advanced
Found _
Where : www.VB-Helper.com
Notice: If any code is missing get the full version here at
http://www.vb-helper.com/howto.htm
--------------------------------------------------------

Option Explicit
Type FileSection
    Bytes() As Byte
    FileLen As Long
End Type
Type SectionedFile
    Files() As FileSection
    NumberOfFiles As Long
End Type
Type FileInfo
    OrigProjSize As Long
    OrigFileName As String
    FileSectionPath As String
    FileCount As Integer
    FileStartNum As Long
End Type

Public Function SplitFile(SplitFileName As String, _
BeginningNumber As Long, ReturnErrorDes As String, Optional Split As Long = _
1439865, Optional OutTemplateName As String) As Boolean
    Dim SaveName As String
    SplitFile = True 'Assume Success
    On Error GoTo CleanUp
    Dim CurrentFile As SectionedFile, m_lngNumFil As Long, m_lngLoop As Long, FilesLen As Long
    FilesLen = FileLen(SplitFileName)
    If FilesLen <= Split + 1 Then
    SplitFile = False 'If the File _
    Name is Smaller than the Split Ratio then _
    The Function Doesnt Need Called So it Fails.
    ReturnErrorDes = "File Is Too Small"
    Exit Function
    End If
    Open SplitFileName For Binary As #1 'I Use #1 as _
    Default Because I Normally Only Open one _
    File At a Time. If needed it can be changed.
        If (FilesLen \ Split) >= _
        FilesLen / Split Or (FilesLen \ Split) _
        = FilesLen / Split Then
            m_lngNumFil = (FilesLen _
            \ Split)  ' If VB heightened(or if they _
            were equal) the length of the file _
            divided by the total Split ratio then _
            nothing needs To Do anything.
        ElseIf (FilesLen \ Split) <= _
        FilesLen / Split Then
            m_lngNumFil = (FilesLen \ _
            Split) + 1 ' If VB Lowered The _
            Length Of the File Divided by the Total _
            Split Ratio then it Will Need To Correct _
            it.
        End If
        ReDim CurrentFile.Files(1 To m_lngNumFil)
        For m_lngLoop = 1 To m_lngNumFil - 1
            ReDim CurrentFile.Files(m_lngLoop) _
                .Bytes(1 To Split) 'Re-Define(Re _
                Dimention) the Number Of Bytes Per _
                File
            CurrentFile.Files(m_lngLoop) _
                .FileLen = UBound(CurrentFile.Files _
                (m_lngLoop).Bytes) 'Just For Reference
        Next
        For m_lngLoop = 1 To m_lngNumFil
            Get #1, , CurrentFile.Files(m_lngLoop) _
            .Bytes
        Next
        ReDim CurrentFile.Files(m_lngNumFil) _
            .Bytes(1 To FilesLen - ((m_lngNumFil _
            - 1) * Split)) 'ReDefine the Number of _
            bytes for the last file since in many cases _
            it will not be at the Split ratio.
        CurrentFile.NumberOfFiles = m_lngNumFil
        Get #1, , CurrentFile.Files(m_lngNumFil) _
            .Bytes
        CurrentFile.Files(m_lngNumFil) _
            .FileLen = UBound(CurrentFile.Files _
            (m_lngNumFil).Bytes)
    Close #1 'Close File(1)
    For m_lngLoop = 1 To CurrentFile.NumberOfFiles _
    'Save What We Have Done Into Seperate Files
        SaveName = FilePath(OutTemplateName) & ReturnFileName(SplitFileName) & "." & Format(BeginningNumber - 1 + m_lngLoop, _
        "00#")
        Open SaveName For Binary As #1
            Put #1, 1, CurrentFile.Files(m_lngLoop)
        Close #1
    Next
    Dim FileInfoFile As FileInfo
    FileInfoFile.FileCount = m_lngNumFil
    FileInfoFile.OrigFileName = SplitFileName
    FileInfoFile.FileSectionPath = FilePath(SaveName)
    FileInfoFile.OrigProjSize = FileLen(SplitFileName)
    FileInfoFile.FileStartNum = BeginningNumber
    If OutTemplateName = "" Then
    SaveName = SplitFileName & ".tpl"
    Else
    SaveName = OutTemplateName
    End If
    On Error Resume Next
    Open SaveName For Binary As #1
        If Err <> 0 Then ReturnErrorDes = Err.Description _
            : SplitFile = False: Exit Function
        Put #1, , FileInfoFile
    Close #1
    Exit Function
CleanUp:
    ReturnErrorDes = Err.Description
    SplitFile = False
End Function

Public Function ReassembleFile(TemplateFileName As String, _
    Optional UseOldFilename As Boolean = True, Optional _
    OutPutName = "C:\Filname.Extention") As Boolean
    Dim FileInfo As FileInfo, OutName As String, File As _
    SectionedFile, m_lngLoop As Long, OpenName
    ReassembleFile = True 'Assume Success
    If Len(TemplateFileName) = 0 Then ReassembleFile = False: Exit Function
    Open TemplateFileName For Binary As #1
        Get #1, , FileInfo 'Get Information on the _
        Previously Saved File(s)
    Close #1
    If UseOldFilename Then
        OutName = FileInfo.OrigFileName
    Else
        OutName = OutPutName
    End If
    ReDim File.Files(1 To FileInfo.FileCount)
    For m_lngLoop = 1 To FileInfo.FileCount
        OpenName = FileInfo.FileSectionPath & ReturnExtention(FileInfo.OrigFileName, False, "\") & "." & _
        Format((FileInfo.FileStartNum - 1 + _
        m_lngLoop), "00#")
        Open OpenName For Binary As #1
            Get #1, 1, File.Files(m_lngLoop)
        Close #1
    Next
    Open OutName For Binary As #1
        For m_lngLoop = 1 To FileInfo.FileCount
            Put #1, , File.Files(m_lngLoop).Bytes
        Next
    Close #1
End Function

Public Function ReturnFileName(Text As String)
    Dim XText As String, DLines() As String
    XText = Text
    If Not Right(XText, 1) = "\" Then XText = XText & "\"
    SplitDirName CStr(XText), DLines()
    ReturnFileName = DLines(UBound(DLines))
End Function

Public Function FilePath(FileName As String) As String
    Dim XText As String, DFileName As String, m_lngLoop As Long, DLines() As String
    XText = FileName
    If Not Right(XText, 1) = "\" Then XText = XText & "\"
    SplitDirName CStr(XText), DLines()
    For m_lngLoop = 1 To UBound(DLines) - 1
        DFileName = DFileName & DLines(m_lngLoop) & "\"
    Next
    FilePath = DFileName
End Function
Sub SplitDirName(DirName As String, Lines() As String)
'SplitDirName
'Created By Allen
    If DirName = "" Then Exit Sub
    Dim Text As String, CurNum As Long, TotalNum As Long, CurPos As Long
    Text = DirName
    CurNum = 1
    CurPos = 1
    TotalNum = GetCount(Text, "\")
    ReDim Lines(1 To TotalNum)
    Do Until CurNum = TotalNum + 1
        Lines(CurNum) = Mid(Text, 1, InStr(CurPos, Text, "\") - 1)
        Text = Mid(Text, Len(Lines(CurNum)) + 2)
        CurNum = CurNum + 1
    Loop
End Sub

Public Function GetCount(Text As String, Search As String)
    Dim CCnt As Long, m_lngLoop As Long
    For m_lngLoop = 1 To Len(Text)
        If Mid(Text, m_lngLoop, Len(Search)) = Search Then
            CCnt = CCnt + 1
        End If
    Next
    GetCount = CCnt
End Function

--------------------------------------------------------
Note: If you have any comments or questions, E-Mail Me @ allenc_jr@hotmail.com
0
 
LVL 2

Expert Comment

by:AllenC_Jr
ID: 1447655
hmmm, stupid submit button...

0
 
LVL 3

Expert Comment

by:jbil
ID: 1447656
Private Declare Function SetCaretPos Lib "user32" (ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function GetCaretPos Lib "user32" (lppoint As POINTAPI) As Long
Private Type POINTAPI
        X As Long
        Y As Long
End Type

Private Sub Form_Load()
Dim caret As POINTAPI
Dim startpos As Integer
Me.Show

Text1.Text = "Demo of insertion point at left of selected text"
startpos = InStr(1, Text1.Text, "selected", vbTextCompare) - 1
Text1.SelStart = startpos

GetCaretPos caret

Text1.SelLength = Len("selected")

DoEvents
SetCaretPos caret.X, caret.Y
End Sub






0
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
LVL 1

Author Comment

by:Chamberlain
ID: 1447657
This is nice code, and the closest I have seen.  Unfortunately, it only changes the caret position.  it doesn't change the insertion point.  In the example code, the caret is placed before the word "Selected" but the insertion point is still after it.  If you hit the left arrow key, the caret moves before the "d" not the space before the word.  I started looking at these APIs initially and ended up turning away from them.  It's almost like one level too far in.  These are APIs that the ThunderTextBox uses internally to present where it's insertion property is.  I think we need to back up and instruct the ThunderTextBox to change it's insertion point and then it would call these APIs to place the caret in the correct place.
0
 

Expert Comment

by:budgie_b
ID: 1447658
Remove the text1.SelLength = Len("selected") of the above code to get your insertion point?
0
 
LVL 1

Author Comment

by:Chamberlain
ID: 1447659
Yeah, but then the text isn't selected which is the whole reason for this discussion.
0
 

Expert Comment

by:budgie_b
ID: 1447660
All I can see you can do is add the startpos again to the Text1 keydown event?  Am I wasting your time?
0
 
LVL 1

Author Comment

by:Chamberlain
ID: 1447661
Changing SelStart sets SelLength to 0.  I really don't think there is a way to do it with regular VB.  It requires API calls much like what JBIL presented.  Unfortuanely his overrode the Caret's placement, it didn't change the insertion point.
0
 

Accepted Solution

by:
millej earned 150 total points
ID: 1447662
Dude...try this....

Just pass the text box, start and end positions like this:

Call MySetSel(Me.Text1, 0, 5)   'select first 5 characters with insertion point at end
Call MySetSet(Me.Text1, 5, 0)    'select first 5 characters with insertion point at front

Note this will only work with Textboxes where MultiLine = True.  
*****cut & paste from here on*******

Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Const EM_SETSEL = &HB1

Public Sub MySetSel(ctrl As TextBox, StartPos As Long, EndPos As Long)

ctrl.SetFocus
Call SendMessage(ctrl.hwnd, EM_SETSEL, ByVal StartPos, ByVal EndPos)

End Sub
0
 
LVL 1

Author Comment

by:Chamberlain
ID: 1447663
Awesome!  How come it only works with MultiLine on?  Can it be set to work with it off.  I can always capture and discard the carriage return but was curious.  I'm going to give you the points, but if you can tell me how to do it with multiline off,
I'll give you 200 points.
0
 

Expert Comment

by:millej
ID: 1447664
the EM_SETSEL message ignores the order of the start/end positions when MultiLine is False.  Seems dumb to me too, you'd have to ask Microsoft why it's implemented that way.
0
 

Expert Comment

by:millej
ID: 1447665
the EM_SETSEL message ignores the order of the start/end positions when MultiLine is False.  Seems dumb to me too, you'd have to ask Microsoft why it's implemented that way.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Introduction I needed to skip over some file processing within a For...Next loop in some old production code and wished that VB (classic) had a statement that would drop down to the end of the current iteration, bypassing the statements that were c…
Introduction In a recent article (http://www.experts-exchange.com/A_7811-A-Better-Concatenate-Function.html) for the Excel community, I showed an improved version of the Excel Concatenate() function.  While writing that article I realized that no o…
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…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

758 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

18 Experts available now in Live!

Get 1:1 Help Now