Forum > LCL

TMemo, caret position and selection

(1/1)

RobA:
Hi all,

I'm using Lazarus 2.0.12 on Windows 10.

I have a TMemo on a form, and want to track the caret position in the format row nn : col nn.

I'm handling OnChnage, OnKeyDown, OnKeyUp and also mouse events, calling a procedure that updates a TStatusBar with the Memo's caret position from each event handler:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---StatusBar1.Panels[0].Text:= 'Row '+ IntToStr(TheMemo.CaretPos.y+1) + ' : Col '+IntToStr(TheMemo.caretPos.x+1);
This works, in that moving the caret around with the cursor keys, typing text, or clicking the mouse gives the correct caret position. However, things go a bit awry when I hold down shift to select some text. Suppose I have the following two lines of text in the Memo:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
If I move the caret to the middle of a line, hold down shift and move the cursor to the right, the caret position reflects the end of the selection. If I hold down shift and move to the left, the caret position doesn't change, even though there is a blinking caret at the left end of the selection. If I position the caret in the second line (say, immediately before the letter p, then hold down shift and move up a line, such that the selection starts with "p" in the first line and ends with "o" in the second line, the caret position is reported as Row 2 : Col 44.

I'm guessing I could probably work around that somehow with SelStart and SelLength, but SelStart returns a character index into the text of the Memo. How can I convert that back to a line number? I don't see any equivalent of EM_LINEFROMCHAR?

I'm probably overlooking something really obvious here, but any suggestions would be very much appreciated.

TIA

Rob.

jamie:
You will not get a line for line representation using a memo in windows.

if any line happens to wrap around then all lines after that are move down in count..

Windows treats the memo as one long single string with the line endings in the middle of it, so to get real line numbers you need to use window memo control messages to obtain that or use the lines property which is a stringlist but that of course does not follow the 1:1 line number between screen and stringlist

winni:
Hi!

You have to use
--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- Memo1.caretpos
which returns  a point that gives you the line (y) and the row (x)

Winni

MarkMLl:

--- Quote from: winni on November 29, 2021, 10:35:19 pm ---You have to use
--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- Memo1.caretpos
which returns  a point that gives you the line (y) and the row (x)

--- End quote ---

Noting that in this case "point" is defined in terms of characters/lines rather than pixels.

https://lazarus-ccr.sourceforge.io/docs/lcl/stdctrls/tcustomedit.caretpos.html

MarkMLl

RobA:
Hi all,

Many thanks for your suggestions. As I mentioned in the original post, I was already using CaretPos, and found some strange values with selected text (nothing's ever straight forward, is it? :) )

I finally came up with the following procedure, called from event handlers for OnChnage, OnKeyDown, OnKeyUp and also mouse events. TheMemo is the TMemo in question, and SelBegin is a global variable that gets the caret position when a selection is first begun.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---     LineIndex := SendMessage(TheMemo.Handle,EM_LINEINDEX,-1,0);     if TheMemo.SelLength = 0 then     begin        Col := TheMemo.SelStart - LineIndex;        SelBegin := TheMemo.SelStart;        Row := SendMessage(TheMemo.Handle,EM_LINEFROMCHAR,TheMemo.SelStart,0);     end     else     begin       if TheMemo.SelStart < SelBegin then          Col := TheMemo.SelStart - LineIndex       else           Col := (TheMemo.SelStart + TheMemo.SelLength) - LineIndex;       Row := SendMessage(TheMemo.Handle,EM_LINEFROMCHAR,TheMemo.SelStart+TheMemo.SelLength,0);     end;     StatusBar1.Panels[0].Text:= 'Row '+ IntToStr(Row + 1) + ' : Col '+IntToStr(Col + 1);
I'm a little rusty on Pascal, so if anyone has any thoughts for improvements, I'd love to hear them.

Navigation

[0] Message Index

Go to full version