MultiLine field & Rich Text
How to place the cursor at a specific location in the text, text selection and insertion
This applies for datafields and multilines.
Using Windows API messages you can do the following:
- Set the cursor/caret at a specific location within the text
- Select a portion or all of the text
- Insert text at a specific location within the text
- Replace a preselected portion of text with another text
- Delete a preselected portion of text
- Get the current location/selection of text
First define these WinApi constants
Number: EM_GETSEL = 0x00B0 Number: EM_SETSEL = 0x00B1 Number: EM_SCROLLCARET = 0x00B7 Number: EM_REPLACESEL = 0x00C2
Place the cursor/caret at a specific character location
The first character position from the left is 0 (zero).
To position the cursor/caret to a specific location, send EM_SETSEL message to the field having wParam and lParam the same value.
! Place the cursor at position 200 in the text. Set left and right position at the same value Set nLeftPos = 200 Set nRightPos = 200 Call SalSendMsg( hWndField, EM_SETSEL, nLeftPos, nRightPos ) ! ! When the cursor is out of view, the field does not scroll automatically, so you should scroll it by using : Call SalSendMsg( hWndField, EM_SCROLLCARET, 0, 0 )
To set the cursor at the end of the text, use -1 in wParam and lParam.
Select portion of the text
For this you have to define the starting and ending character position.
The wParam holds the start and lParam the end position.
Set nLeftPos = 200 Set nRightPos = 210 Call SalSendMsg( hWndField, EM_SETSEL, nLeftPos, nRightPos )
To select all the text in the field, use wParam = 0 and lParam = -1
To deselect the text, use -1 as value for wParam and lParam.
Call SalSendMsg( hWndField, EM_SETSEL, -1, -1 )
Insert text at a specific location
First place the cursor at the location you want to insert new text (see above).
Then send the EM_REPLACESEL message to the field using VisSendMsgString.
! Place the cursor at position 200 in the text. Set left and right position at the same value Set nLeftPos = 200 Set nRightPos = 200 Call SalSendMsg( hWndField, EM_SETSEL, nLeftPos, nRightPos ) ! ! Now insert some text at the current caret position Call VisSendMsgString( hWndField, EM_REPLACESEL, TRUE, "This will be inserted" )
Replace text which is selected
Like above except use the appropriate nLeftPos and nRightPos values.
So first select the part of the text and then send the EM_REPLACESEL message.
Get the current position/selection boundaries
Send the EM_GETSEL message to the field.
It will return the start and end position of the cursor/caret.
The return value contains the start position in Low number and end position in the High number.
Set nReturn = SalSendMsg( hWndField, EM_GETSEL, 0, 0 ) ! Set nLeftPos = SalNumberLow( nReturn ) Set nRightPos = SalNumberHigh( nReturn )
If no selections are performed above, you should first set the focus to the field
Call SalSetFocus( hWndField )
Here you can download a sample:
How to make a scrollable but disabled multiline
When you disable the field, the scrollbars are also disabled.
Use this instead to have scrolling
Call VisWinSetFlags ( hWndField, WF_DisplayOnly, TRUE )
Fast and smooth autoscroll multiline text appending
A common way to append text to a multiline field is to concatenate the text to the multiline field.
Set mlOutput = mlOutput || "Some text to append"
In some cases you could need to show the appended text, to put it into view.
For instance when displaying large amounts of text like for logging/tracing, a realtime and automatic scroll into view is preferable.
To do this, you need to programatically move the vertical thumb of the scrollbar to the bottom after the text is populated.
This is done by sending a message to the multiline field like this:
! Used WinApi constants Number: WM_VSCROLL = 0x0115 Number: SB_BOTTOM = 7 ! Scroll the vertical thumb scrollbar to the bottom Call SalSendMsg( mlOutput, WM_VSCROLL, SB_BOTTOM, NUMBER_Null )
This works, the last text line in the multiline will be scrolled into view.
But when looking closely while populating, the multiline does this not very smoothly. For example the scroll thumb seems to
jump from top to bottom and the text has a flicker. This gives a somewhat unprofessional look & feel.
But another issue: the population is also not as fast as it could be.
To solve this we need another way to append the text. What actually happens when you append text to the multiline like above is that
the field is internally cleared. It is repopulated with the complete new text on every append. This results in the scrollbar jump
to the top and bottom when the new text is placed into the field and causes the text flickering.
Using WinApi, we can actually insert a new text at a specific position in the multiline field.
Position the caret (cursor) at the end of the text in the multiline and then insert the text.
First we need to position the caret at the end, doing this:
! Used WinApi constant Number: EM_SETSEL = 0x00B1 ! Set the caret at the end of the current text in the multiline Call SalSendMsg( mlOutput, EM_SETSEL, -1, -1 )
Now we need to insert the text at caret position:
! Used WinApi constant Number: EM_REPLACESEL = 0x00C2 ! Insert the text at the caret position. This will keep the text in the field and only insert the text at the end ! Include vtmisc.apl for the Vis function Call VisSendMsgString( mlOutput, EM_REPLACESEL, TRUE, "Text to append" )
After this, the text is appended in the field. Only next action is to scroll it into view by sending WM_VSCROLL to the field
as described above.
This in fact will not only make the population smoother and less flicker, but also much faster.
Here you can download a sample: