Recent

Author Topic: Is there some property to help retrieve the current line from a Memo?  (Read 5452 times)

vfclists

  • Hero Member
  • *****
  • Posts: 1147
    • HowTos Considered Harmful?
The CaretPos.Y property used to obtain the current line in the memo is not defined for the Qt widget set.

Is there some other method to work it out? What other propertites or methods can be used to obtain it? eg can the SelStart property be used as startin point, or some other function which computes the character position?
Lazarus 3.0/FPC 3.2.2

typo

  • Hero Member
  • *****
  • Posts: 3051
Use SynEdit.

vfclists

  • Hero Member
  • *****
  • Posts: 1147
    • HowTos Considered Harmful?
Use SynEdit.

SynEdit does not have word wrapping which I really need.
Lazarus 3.0/FPC 3.2.2

rvk

  • Hero Member
  • *****
  • Posts: 6726
Is there some other method to work it out?
...
eg can the SelStart property be used as startin point, or some other function which computes the character position?
In GTK it does work (internally gtk_text_iter_get_line is used for a Memo).

You could use the SelStart and count the number of #13's (from 0 to SelStart). It's a crude method and only works for small texts but should work.

For instance, you could do this:
Code: [Select]
function OccurrencesOfChar(const S: string; const C: char): integer;
var
  i: Integer;
begin
  result := 0;
  for i := 1 to Length(S) do
    if S[i] = C then
      inc(result);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Line: Integer;
begin
  Line := OccurrencesOfChar(Copy(Memo1.Text, 1, Memo1.SelStart), #13);
  Showmessage('Line: ' + IntToStr(Line) + ' = ' + Memo1.Lines[Line]);
end;

(Note: Line is 0 based)

Edit: Woops. I'm not sure how you would like the count to be with line-wrapping? Above method doesn't take into account the line could be wrapped.

Do you need the real line-number or just the string-text of the line where your caret is at?

If that's the case you could do something like this:
Code: [Select]
function GetCurrentLineString(Memo: TMemo): String;
var
  bChar, eChar: Integer;
begin
  bChar := Memo.SelStart;
  while (bChar > 0) and (Copy(Memo.Text, bChar - 1, 1) <> #13) do Dec(bChar);
  eChar := bChar;
  while (eChar < Length(Memo.Text)) and (Copy(Memo.Text, eChar + 1, 1) <> #13) do Inc(eChar);
  Result := Copy(Memo.Text, bChar, eChar - bChar + 1);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Showmessage('Line: ' + GetCurrentLineString(Memo1));
end;

(Note: A line does include the entire line, even if it's wrapped)
« Last Edit: May 11, 2015, 12:16:14 pm by rvk »

vfclists

  • Hero Member
  • *****
  • Posts: 1147
    • HowTos Considered Harmful?
Is there some other method to work it out?
...
eg can the SelStart property be used as startin point, or some other function which computes the character position?
Code: [Select]
function GetCurrentLineString(Memo: TMemo): String;
var
  bChar, eChar: Integer;
begin
  bChar := Memo.SelStart;
  while (bChar > 0) and (Copy(Memo.Text, bChar - 1, 1) <> #10) do Dec(bChar);
  eChar := bChar;
  while (eChar < Length(Memo.Text)) and (Copy(Memo.Text, eChar + 1, 1) <> #10) do Inc(eChar);
  Result := Copy(Memo.Text, bChar, eChar - bChar + 1);
end;

...


I have tested GetCurrentLineString and it works, however the character tested should be #10,EOL not #13,CR. I think DOS uses #13#10 sequence, so #10 is the one to check on both Linux and Windows.

Update: Zeljko has updated SVN with a fix for Qt . r48988. http://forum.lazarus.freepascal.org/index.php/topic,28374.msg177528.html#msg177528. I will test  it as soon as I can.
Lazarus 3.0/FPC 3.2.2

rvk

  • Hero Member
  • *****
  • Posts: 6726
I have tested GetCurrentLineString and it works, however the character tested should be #10,EOL not #13,CR. I think DOS uses #13#10 sequence, so #10 is the one to check on both Linux and Windows.

Or you could test for both #10 and #13. That way you're sure it's going to work:

Code: [Select]
function GetCurrentLineString(Memo: TMemo): String;
var
  bChar, eChar: Integer;
begin
  if Memo.Text = '' then exit;
  bChar := Memo.SelStart;
  while (bChar > 0) and not(Memo.Text[bChar - 1] in [#10,#13]) do Dec(bChar);
  eChar := bChar;
  while (eChar < Length(Memo.Text)) and not(Memo.Text[eChar + 1] in [#10,#13]) do Inc(eChar);
  Result := Copy(Memo.Text, bChar, eChar - bChar + 1);
end;

Quote
Update: Zeljko has updated SVN with a fix for Qt . r48988. http://forum.lazarus.freepascal.org/index.php/topic,28374.msg177528.html#msg177528. I will test  it as soon as I can.

There is something else to consider. Do you want the entire line (the not-wrapped one)? Or do you want only the part of the string that's visible on that line. TMemo.Lines wraps lines and in the Lines property the lines are already broken up (at least with my initial testing). So if you want the unwrapped line (from #10 to #10) you still should use the GetCurrentLineString-function.

typo

  • Hero Member
  • *****
  • Posts: 3051
SynEdit does not have word wrapping which I really need.

Now you could wrap text with UTF8WrapText function from LazUTF8 unit.
« Last Edit: May 11, 2015, 07:23:06 pm by typo »

vfclists

  • Hero Member
  • *****
  • Posts: 1147
    • HowTos Considered Harmful?
When Memo widgets implement Word wrap do they insert carriage line feeds or carriage returns which the keep track of and remove when the text is edited, or do they calculate how many characters can fit and continue them on the next line?

Some of the comments seem to suggest that word wrapping puts line breaks to cause the wrapping, which are removed later on.
Lazarus 3.0/FPC 3.2.2

typo

  • Hero Member
  • *****
  • Posts: 3051
They are not removed.

AFAIK, there is no way to break a line without LineEnding insertion.
« Last Edit: May 11, 2015, 07:54:49 pm by typo »

vfclists

  • Hero Member
  • *****
  • Posts: 1147
    • HowTos Considered Harmful?
They are not removed.

AFAIK, there is no way to break a line without LineEnding insertion.

I thought word wrapping in editors was based on functions which work out how much of a line can be displayed according to the window with and continues the rest on the next line without actually inserting line feeds.

Does the UTF8WrapText work on the TSynEdit and TMemo controls, or is it a function that takes a string list and breaks them at some character length?
Lazarus 3.0/FPC 3.2.2

typo

  • Hero Member
  • *****
  • Posts: 3051
Code: [Select]
function UTF8WrapText(S :string; MaxCol: integer): string;

It takes a string and break it on every MaxCol value.

sfeinst

  • Full Member
  • ***
  • Posts: 237
I would not hardcode any line ending in your code.  You should use the constant LineEnding.  That way your code should work on any OS.

In any case, basing on Line Ending may not be best either because of word wrap.  I just checked out notepad in Windows, which I think uses the same underlying control as TMemo (don't quote me on that as I don't know for sure).  Interestingly, notepad turns off goto line when word wrapping is on.  Hinting that finding line number with word wrap can be a pain.

What is the purpose for getting the line?  There might be a better way to do what you want.  If it is just to display a line number on the screen, then as the user of your app, you need to decide how you want the word wrapping to affect that value.  But if you want the line number for a different purpose, it would be helpful to know what that is.

typo

  • Hero Member
  • *****
  • Posts: 3051
You could use also lzRichEdit:

http://wiki.lazarus.freepascal.org/lzRichEdit

 

TinyPortal © 2005-2018