Basic 1: Get Text/Boundaries: AllText, Selection, Caret, Current Line, LineM, LinesM-N, CharsM-N

Category: Controls - RichEdit

Date: 02-16-2022

Return to Index

'This code shows how to get various text areas and the corresponding char/line boundaries -
'all text, selection, caret, current line, LinesM, LineM-N, CharM and CharsM-N.
'Both DDT and direct API solutions are provided.
'Compiler Comments:
'This code is written to compile with PBWin10. To compile with PBWin9,
'add this line:
#Include ""
'Primary Code:
'Because of size, only a single copy of the primary code is shown, as part
'of the compilable example below.  All code is shown as Functions.
'But, in summary, here are the basic statements used. These can be used
'individually to get information, whereas the Functions in the compilable example
'below return several pieces of information with each call.
   Control Get Text    'used to get entire text of RichEdit control
   Instr                 'find start/end positions of lines
   ParseCount           'determine how many lines are in the control text
   Parse$               'retrieve specific line content
   SendMessage(hRichEdit, %EM_EXGetSel, 0, VarPTR(P))          'start/stop of selection, caret position if no selection
   SendMessage(hRichEdit, %EM_LineIndex, n&, 0)                'position of 1st char in line m&
   SendMessage(hRichEdit, %EM_LineLength, iStartPos&, 0)       'length of specified line
   SendMessage(hRichEdit, %EM_GetTextLengthEX, VarPTR(D),0)    'length of all text in control
   SendMessage(hRichEdit, %EM_EXLineFromChar, 0, -1)           'line#, current
   SendMessage(hRichEdit, %EM_EXLineFromChar, 0, iStartPos&)   'line# containing specified character
   SendMessage(hRichEdit, %EM_GetLineCount, 0,0)                   'total line count in control
   SendMessage(hRichEdit, %EM_GetLine, iStartLine&, StrPTR(buf$))  'get text, specified line
   SendMessage(hRichEdit, %EM_GetSelText, 0, StrPTR(buf$))         'get text, selected
   SendMessage(hRichEdit, %EM_GetTextEX, VarPTR(T), StrPTR(buf$))  'get text, specified char range or from selection
'Compilable Example:  (Jose Includes)
'This example gets all of the text, the selected text, text from specific
'lines or character positions, character/Line positions of selections, and
'character/line position of the caret.  Both DDT and SKD solutions are
'demonstrated in the example.
'Line numbers start at 0. 'Char positions start at 0.
'Char positions include $crlf at end of previous lines.
'If there is no selection, the selection function returns the caret position.
'If there is a selection, the caret function returns the starting position of the selection.
#Compiler PBWin 10
#Compile EXE
#Dim All
#Include "
#Include ""
Global hDlg as DWord, hRichEdit as DWord
%ID_RichEdit = 500
Function PBMain() As Long
   Local style&, buf$
   buf$ =  "This is sample" + $CrLf + "text for the" + $CrLf + "edit control."
   style& = %WS_Child Or %WS_Visible Or %ES_MultiLine Or %WS_VScroll Or %ES_AutoHScroll _
      Or %WS_HScroll Or %ES_AutoVScroll Or %ES_WantReturn Or %ES_NoHideSel Or %WS_TabStop
   Dialog New Pixels, 0, "Test Code",300,300,200,330, %WS_OverlappedWindow To hDlg
   LoadLibrary("riched32.dll") : InitCommonControls
   Control Add "RichEdit", hDlg, %ID_RichEdit, buf$,20,10,160,50, style&, %WS_EX_ClientEdge
   Control Handle hDlg, %ID_RichEdit To hRichEdit
   Control Add Button, hDlg, 100,"All DDT", 10,70,80,20 : Control Add Button, hDlg, 180,"Line 1 DDT", 100,70,90,20
   Control Add Button, hDlg, 110,"All API", 10,100,80,20 : Control Add Button, hDlg, 190,"Line 1 API", 100,100,90,20
   Control Add Button, hDlg, 120,"Sel DDT", 10,130,80,20 : Control Add Button, hDlg, 200,"Lines 0-1 DDT", 100,130,90,20
   Control Add Button, hDlg, 130,"Sel API", 10,160,80,20 : Control Add Button, hDlg, 210,"Lines 0-1 API", 100,160,90,20
   Control Add Button, hDlg, 140,"Caret DDT", 10,190,80,20 : Control Add Button, hDlg, 210,"Chars 11-11 DDT", 100,190,90,20
   Control Add Button, hDlg, 150,"Caret API", 10,220,80,20 : Control Add Button, hDlg, 220,"Chars 11-11 API", 100,220,90,20
   Control Add Button, hDlg, 160,"Current Ln DDT", 10,250,80,20 : Control Add Button, hDlg, 230,"Chars 10-20 DDT", 100,250,90,20
   Control Add Button, hDlg, 170,"Current Ln API", 10,280,80,20 : Control Add Button, hDlg, 240,"Chars 10-20 API", 100,280,90,20
   Control Add Button, hDlg, 240,"Restore", 100,310,80,20
   Dialog Show Modal hDlg Call DlgProc
End Function
CallBack Function DlgProc() As Long
   Local iStartPos&, iStopPos&, iStartLine&, iStopLine&
   If CB.Msg = %WM_Command AND CB.Ctl = 100 Then GetTextBoundary_AllText_DDT hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine&   'all text replaced
   If CB.Msg = %WM_Command AND CB.Ctl = 110 Then GetTextBoundary_AllText_API hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine&   'all text replaced"
   If CB.Msg = %WM_Command AND CB.Ctl = 120 Then GetTextBoundary_Selection_DDT hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'selection replaced"
   If CB.Msg = %WM_Command AND CB.Ctl = 130 Then GetTextBoundary_Selection_API hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'selection replaced"
   If CB.Msg = %WM_Command AND CB.Ctl = 140 Then GetTextBoundary_CurrentLine_DDT hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'current line"
   If CB.Msg = %WM_Command AND CB.Ctl = 150 Then GetTextBoundary_CurrentLine_API hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'current line"
   If CB.Msg = %WM_Command AND CB.Ctl = 160 Then GetTextBoundary_LinesMN_DDT hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'Line 1 replaced"
   If CB.Msg = %WM_Command AND CB.Ctl = 170 Then GetTextBoundary_LinesMN_API hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'Line 1 replaced"
   If CB.Msg = %WM_Command AND CB.Ctl = 180 Then GetTextBoundary_LinesMN_DDT hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'Lines 0,1 replaced"
   If CB.Msg = %WM_Command AND CB.Ctl = 190 Then GetTextBoundary_LinesMN_API hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'Lines 0,1 replaced"
   If CB.Msg = %WM_Command AND CB.Ctl = 200 Then GetTextBoundary_CharsMN_DDT hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'XX"
   If CB.Msg = %WM_Command AND CB.Ctl = 210 Then GetTextBoundary_CharsMN_API hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'XX"
   If CB.Msg = %WM_Command AND CB.Ctl = 220 Then GetTextBoundary_CharsMN_DDT hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'Chars 10,20 replaced"
   If CB.Msg = %WM_Command AND CB.Ctl = 230 Then GetTextBoundary_CharsMN_API hRichEdit, iStartPos&, iStopPos&, iStartLine&, iStopLine& 'Chars 10,20 replaced"
   If CB.Msg = %WM_Command AND CB.Ctl = 240 Then Control Set Text hDlg, %ID_RichEdit, "This is sample" + $CrLf + "text for the" + $CrLf + "edit control."
End Function
Function GetTextBoundary_AllText_DDT(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   'returns all text in control, 1st/last char pos, 1st/last/line #
   'char #'s are zero-based. line #'s are zero-based.
   Local temp$
   Control Get Text hDlg, %ID_RichEdit To temp$
   iStartPos& = 0 : iStopPos& = Len(temp$) - 1
   iStartLine& = 0  : iStopLine& = ParseCount(temp$, $crlf) -1
   Function = temp$
   DisplayResult ("All-DDT", temp$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Function GetTextBoundary_AllText_API(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   Local D as GetTextLengthEX, T as TextRange, iLengthText&, buf$
   D.flags = %GTL_Default                                                             'return number of characters
   iLengthText& = SendMessage(hRichEdit, %EM_GetTextLengthEX, VarPTR(D),0)  'total length (# char's in control)
   buf$ = Space$(iLengthText&)
   iStartPos& = 0
   iStopPos& = iLengthText& - 1
   iStartLine& = 0
   iStopLine& = SendMessage(hRichEdit, %EM_GetLineCount, 0,0) - 1
   T.Chrg.cpmin = iStartPos& : T.Chrg.cpmax = iStopPos& - 1
   SendMessage(hRichEdit, %EM_GetTextEX, VarPTR(T), StrPTR(buf$))   'returns all chars in buf$
   Function = buf$
   DisplayResult ("All-API", buf$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Function GetTextBoundary_Selection_DDT(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   Local temp$
   'DDT Requires some API code to work
   DisplayResult ("Selection-DDT", temp$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Function GetTextBoundary_Selection_API(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   Local P as CharRange, iResult&, buf$
   iResult& = SendMessage(hRichEdit, %EM_EXGetSel, 0, VarPTR(P))       'start/stop of selection, caret position if no selection
   iStartPos& = P.cpmin
   iStopPos& = P.cpmax
   iStartLine& = SendMessage(hRichEdit, %EM_EXLineFromChar, 0, iStartPos&)    'line containing iStartPos&
   iStopLine& = SendMessage(hRichEdit, %EM_EXLineFromChar, 0, iStopPos&)    'line containing iStopPos&
   buf$ = Space$(iStopPos& - iStartPos& +1)
   SendMessage(hRichEdit, %EM_GetSelText, 0, StrPTR(buf$))   'selection start/stop, caret if none
   Function = buf$
   DisplayResult ("Selection-API", buf$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Function GetTextBoundary_Caret_DDT(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   Local temp$
   'DDT - there is no PowerBASIC DDT command for getting the caret location
   DisplayResult ("Caret-DDT", temp$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Function GetTextBoundary_Caret_API(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   Local P as CharRange, iResult&
   iResult& = SendMessage(hRichEdit, %EM_EXGetSel, 0, VarPTR(P))       'start/stop of selection, caret position if no selection
   iStartPos& = P.cpmin
   iStopPos& = P.cpmin
   iStartLine& = SendMessage(hRichEdit, %EM_EXLineFromChar, 0, iStartPos&)    'line containing iStartPos&
   '   iStartLine& = SendMessage(hRichEdit, %EM_EXLineFromChar, 0, -1)            'current line# / 1st line# of selection
   iStopLine& = iStartLine&                        'caret covers only 1 line
   Function = ""
   DisplayResult ("Caret-API", "<caret>", iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Function GetTextBoundary_CurrentLine_DDT(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   Local temp$
   'DDT - there is no PowerBASIC DDT command for getting the current line
   DisplayResult ("CurrentLine-DDT", temp$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Function GetTextBoundary_CurrentLine_API(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   Local buf$, iLengthText&
   iStartLine& = SendMessage(hRichEdit, %EM_EXLineFromChar, 0, -1)        'current line# or 1st line# of selection
   iStartPos& = SendMessage(hRichEdit, %EM_EXLineFromChar, 0, iStartLine&)    '1st char of current line
   iLengthText& = SendMessage(hRichEdit, %EM_LineLength, iStartPos&, 0)   'length of current line
   iStopPos& = iStartPos& + iLengthText& - 1                                   'last char of current line
   iStopLine& = iStartLine&                                                         'same as current line
   buf$ = Space$(iLengthText&)
   SendMessage(hRichEdit, %EM_GetLine, iStartLine&, StrPTR(buf$))          'entire line of text
   Function = buf$
   DisplayResult ("CurrentLine-API", buf$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Function GetTextBoundary_LinesMN_DDT(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   Local iLengthText&, temp$, i as Long
   Control Get Text hDlg, %ID_RichEdit To temp$
   For i = 1 to 4 : iStartPos& = Instr(iStartPos&, temp$, $crlf) : Next i
   iStartPos& = iStartPos& + 3                         '1st character of line m
   temp$ = Parse$(temp$, $crlf, iStartLine&)           'text of line m
   iStopPos& = iStartPos& + Len(temp$) - 1             'last character of line m
   DisplayResult ("LinesMN-DDT", temp$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Function GetTextBoundary_LinesMN_API(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   Local buf$, iLineNLength&, iCharPosN&
   iStartPos& = SendMessage(hRichEdit, %EM_LineIndex, iStartLine&, 0)              'position of 1st char in line m&
   iCharPosN& = SendMessage(hRichEdit, %EM_LineIndex, iStopLine&, 0)              'position of 1st char in line m&
   iLineNLength& = SendMessage(hRichEdit, %EM_LineLength, iCharPosN&, 0)   'length of line starting at that char position
   iStopPos& = iCharPosN& + iLineNLength& - 1
   buf$ = Space$(iStopPos& - iStartPos& - 1)
   SendMessage(hRichEdit, %EM_GetLine, iStartLine&, StrPTR(buf$))          'entire line of text
   Function = buf$
   DisplayResult ("LinesMN-API", buf$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Function GetTextBoundary_CharsMN_DDT(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   Local iLengthText&, temp$, i as Long
   Control Get Text hDlg, %ID_RichEdit To temp$
   For i = 1 to 4 : iStartPos& = Instr(iStartPos&, temp$, $crlf) : Next i
   iStartPos& = iStartPos& + 3                         '1st character of line m
   temp$ = Parse$(temp$, $crlf, iStartLine&)           'text of line m
   iStopPos& = iStartPos& + Len(temp$) - 1             'last character of line m
   DisplayResult ("CharsMN-DDT", temp$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Function GetTextBoundary_CharsMN_API(ByVal hRichEdit as DWord, iStartPos&, iStopPos&, iStartLine&, iStopLine&) As String
   Local buf$, iLineNLength&, iCharPosN&
   iStartPos& = SendMessage(hRichEdit, %EM_LineIndex, iStartLine&, 0)              'position of 1st char in line m&
   iCharPosN& = SendMessage(hRichEdit, %EM_LineIndex, iStopLine&, 0)              'position of 1st char in line m&
   iLineNLength& = SendMessage(hRichEdit, %EM_LineLength, iCharPosN&, 0)   'length of line starting at that char position
   iStopPos& = iCharPosN& + iLineNLength& - 1
   buf$ = Space$(iStopPos& - iStartPos& + 1)
   SendMessage(hRichEdit, %EM_GetLine, iStartLine&, StrPTR(buf$))          'entire line of text
   Function = buf$
   DisplayResult ("CharsMN-API", buf$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
End Function
Sub DisplayResult (desc$, temp$, iStartPos&, iStopPos&, iStartLine&, iStopLine&)
   MsgBox desc$ + $crlf + $crlf + temp$ + $crlf + $crlf + "StartPos " + Str$(iStartPos&) + $crlf  _
      + "EndPos " + Str$(iStopPos&) + $crlf _
      + "StartLine " + Str$(iStartLine&) + $crlf  _
      + "EndLine " + Str$(iStopLine&)
End Sub
'Date: 03-10-2012

created by gbSnippets