We help IT Professionals succeed at work.

displaying current cursor position on status bar

albireo77
albireo77 asked
on
Medium Priority
2,389 Views
Last Modified: 2012-06-27
Hi,

I am creating editor based on TSynMemo component from SynEdit suite. This component is similar to TMemo. I would like to write current row/column on status bar. To do so I have to put code in many, many places (OnKeyUp, OnClicked etc.) and it still doesn't work as expected in some situations. In TRichEdit control there's OnSelectionChange event which is best for such activity. Unfortunately neither in TSynMemo nor in TMemo this event exists. So my question - what is the best way to catch row/column (or SelStart) while editing text in TMemo.

Albi
Comment
Watch Question

You could subclass the window and trigger to the EM_SETSEL message which sets the caret (that is what you are talking about).
ZhaawZSoftware Developer

Commented:
nope, processing em_setsel does not work with TMemo (i.e., this message is not sent to TMemo when user "manually" sets cursor pos / selection)

Commented:
hello albireo77, , I do not remember  an API message for and mutiline edit to happen foe a claret change position?
Anyway, here is some code that can read out the claret position for a TMemo


procedure TForm2.SetLineNum;
var
MesRe, ChPos, Line: Integer;
begin // this gets the position and does a Label1 caption for claret position
MesRe := Memo1.Perform(EM_GETSEL, 0, 0);
ChPos := HIWORD(MesRe);
Line := Memo1.Perform(EM_LINEFROMCHAR, ChPos, 0);
MesRe := Memo1.Perform(EM_LINEINDEX, Line, 0);
if MesRe < 0 then
  Label1.Caption := '0:0'
  else
  Label1.Caption := IntToStr(Line+1)+' : '+IntToStr(1+ChPos - MesRe);
end;

procedure TForm2.Memo1Change(Sender: TObject);
begin // TMemo OnChange event
SetLineNum;
end;

procedure TForm2.Memo1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin  // OnMouseUp event
SetLineNum;
end;

procedure TForm2.Memo1KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin // OnKeyUp event
if Key in [VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, VK_HOME, VK_END] then
  SetLineNum;
end;

 = = = = = = = = = = = = = = = = = =

this seems to work for me, but there may be other way to change the memo, that is not coded for here.
ask questions if you need more information
ZhaawZSoftware Developer

Commented:
About Slick812's SetLineNum - there's a TMemo().CaretPos that could be used to get "current caret position" - it could be a shorter way than sending those messages...
EM_SETSEL must be sent. TMemo.CaretPos uses it in its implementation.
You could always try the OnStatusChange event, it's always worked fine for me

procedure TForm1.SynMemo1StatusChange(Sender: TObject; Changes: TSynStatusChanges);
var
   p: TPoint;
begin
   if Changes * [scAll, scCaretX, scCaretY] <> [] then
      begin
         p := (Sender as TSynMemo).CaretXY;
         StatusBar1.SimpleText := Format('%6d:%3d', [p.Y, p.X]);
      end;
end;

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts
ZhaawZSoftware Developer

Commented:
robert_marquardt, it uses em_setsel when setting caret position, not getting..


property CaretPos: TPoint read GetCaretPos write SetCaretPos;

function TCustomMemo.GetCaretPos: TPoint;
begin
  Result.X := LongRec(SendMessage(Handle, EM_GETSEL, 0, 0)).Hi;
  Result.Y := SendMessage(Handle, EM_LINEFROMCHAR, Result.X, 0);
  Result.X := Result.X - SendMessage(Handle, EM_LINEINDEX, -1, 0);
end;

procedure TCustomMemo.SetCaretPos(const Value: TPoint);
var
  CharIdx: Integer;
begin
  CharIdx := SendMessage(Handle, EM_LINEINDEX, Value.y, 0) + Value.x;
  SendMessage(Handle, EM_SETSEL, CharIdx, CharIdx);
end;



What I wanted to say in my 1st post was that TMemo does not receive em_setsel each time when selection changes. However, it's possible to set selection with em_setsel, but it does not matter this time.

Commented:
TMemoBar can be attached to a T(Custom)Memo component to provide additional info/functionality for a Memo component, including the current location (row and column) of the caret (textual cursor)

http://delphi.about.com/library/weekly/aa083005a.htm
The TMemo probably does not receive the EM_SETSEL because it is sent to the Windows control TMemo uses.
I meant to subclass that window to catch the EM_SETSEL sent to it. The caret is probably only set via that message. The control sends this message probably also to itself.
You have found a solution so i just want to clarify this.
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.