displaying current cursor position on status bar

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
albireo77Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

robert_marquardtCommented:
You could subclass the window and trigger to the EM_SETSEL message which sets the caret (that is what you are talking about).
ZhaawZSoftware DeveloperCommented:
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)
Slick812Commented:
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
OWASP: Forgery and Phishing

Learn the techniques to avoid forgery and phishing attacks and the types of attacks an application or network may face.

ZhaawZSoftware DeveloperCommented:
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...
robert_marquardtCommented:
EM_SETSEL must be sent. TMemo.CaretPos uses it in its implementation.
HillGrooverCommented:
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;

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ZhaawZSoftware DeveloperCommented:
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.
HardiCommented:
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
robert_marquardtCommented:
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.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.