Recent

Author Topic: Extracting whole string(paragraph) from TMemo and TRichmemo  (Read 7201 times)

egsuh

  • Hero Member
  • *****
  • Posts: 1273
Extracting whole string(paragraph) from TMemo and TRichmemo
« on: January 13, 2019, 02:05:43 am »
Hi,
I tried this on TRichMemo, but I think TMemo will operate in the same way.
When a text string is splitted into two lines in TMemo as the string length is longer than the width of TMemo, it is counted as two (memo1.lines.count). Let's assume that a string is shown as follows in TMemo.

This is an
example.

Then if I execute
   
Code: Pascal  [Select][+][-]
  1. showmessage(memo1.lines[memo1.lines.count-1]);  
  2.  

This will show 'example'.

But when I expand the memo1 width (by setting full window, etc.), then the lines are shown as a single line, and treated as such.

What I want to know is whether there are any way that I can extract the full string from TMemo. For example, a whole string within which the cursor is positioned.

Regards,

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Extracting whole string(paragraph) from TMemo and TRichmemo
« Reply #1 on: January 13, 2019, 03:14:28 am »
I tried with an actual TMemo and can't reproduce. See the attached images: the first one is the memo in full-width, the second is the memo resized (to make it word-wrap) and a call made to:
  ShowDialog(Memo.Lines[Memo.Lines.Count-1]);

I'm using vanilla Lazarus 1.8.4 - i386 Linux GTK2.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Extracting whole string(paragraph) from TMemo and TRichmemo
« Reply #2 on: January 13, 2019, 05:28:40 pm »
The Tmemo is not a very friendly edit box, it steams from the old days and is very limited...

The line numbers are those of what will fit in a memo box views width with out scrollbars.

what you are trying to do involves a little more work..
P :TPoint;

P := Memo1.ScreenTOClient(Mouse.CursorPos);

SomeInteger := SendMessage(Memo1.Handle, EM_CHARFROMPOOS,0,MakeLong(P.X,P.Y));

SomeInteger now reports the position within the text buffer the location of the spot you clicked on for example

from this, you need to traverse left to right until you find the start of a string and the end of the string which are
separated by CR and 0 (nul).
There could already be a method in the MEMO for this...

 If you don't understand that I can maybe I can whip up an example

 Seems like I've done this before but I can't fine the code for it.. Hmm

The only true wisdom is knowing you know nothing

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Extracting whole string(paragraph) from TMemo and TRichmemo
« Reply #3 on: January 13, 2019, 05:34:20 pm »
@jamie: Did you read my post? You don't need so much complexity: TMemo.Lines already has the full lines, whether the view is word-wraped or not.

As for the friendliness of TMemo and its limits .. well, it's all a question of what yo intend to use it for. For small, agile simple-text editors? Almost ideal. :) One such editor in the attached image.
« Last Edit: January 13, 2019, 05:41:09 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Extracting whole string(paragraph) from TMemo and TRichmemo
« Reply #4 on: January 13, 2019, 06:50:07 pm »
I ran a test with Delphi and I can only assume Laz should be the same..

If you Compress the Client window so that line wrapping occurs the end of line 1 ends up being line2

Using the Lines Property will actually generate the end of line one if you reference line 2..

Have you tried indexing the lines by compressing the client window with no scrollbars?

I'll need to test this in Lazarus instead of Delphi, maybe something changed but if that is the case then there
is a lot of software that will break when doing the transition.

yes, verified..

if you have a first line and it wraps around to the next line in the client (View port). the wrapped around portion
becomes Line[1].

Line[0] is the first line but if it gets wrapped out due to no scrollbars the Line[1] becomes the tail end of line[0]

You need to force a line wrap to see this effect.
if this is behaving differently in other widgets then its not compatible in behavior...
Now do you understand what I am talking about ?

« Last Edit: January 13, 2019, 06:59:22 pm by jamie »
The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Extracting whole string(paragraph) from TMemo and TRichmemo
« Reply #5 on: January 13, 2019, 08:45:55 pm »
Here is a sample test that will correctly extract the line when lines are wrapping around..
This test uses the Mouse click as a location to play with..

This may be needed only windows since other widgets may not be suffering from this but this has been around
since I can remember for windows.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Memo1Click(Sender: TObject);
  2. var
  3.   P: Tpoint;
  4.   Index, StartIndex, EndIndex: longint;
  5.   S: string;
  6. begin
  7.   with Sender as Tmemo do
  8.   begin
  9.     P := ScreenToClient(Mouse.CursorPos);//Locate Cursor.
  10.     Index := (SendMessage(handle, EM_CharFromPos, 0, MakeLong(P.X, P.Y)) and $FFFF) + 1;
  11.     //Use only the low part.
  12.     if Index > Length(Text) then
  13.       Exit;
  14.     if (Text[Index] < #14) and (Index > 1) then
  15.       Dec(Index);//Make sure we are not on a end marker.
  16.     StartIndex := Index;
  17.     while (StartIndex > 1) and (Text[StartIndex] > #13) do
  18.       Dec(StartIndex);
  19.     if Text[StartIndex] <= #13 then
  20.       Inc(StartIndex);
  21.     EndIndex := Index;
  22.     while (EndInDex < Length(Text)) and (Text[EndIndex] > #13) and
  23.       (EndIndex < Length(Text)) do
  24.       Inc(EndIndex);
  25.     Setlength(S, EndIndex - StartIndex);
  26.     Index := 1;
  27.     while StartIndex <= EndIndex do
  28.     begin
  29.       S[Index] := Text[StartIndex];
  30.       Inc(Index);
  31.       Inc(StartIndex);
  32.     end;
  33.   end;
  34.   Caption := S;
  35. end;  
  36.  
  37. Drop a memo on the form, give it some lines and make sure they wrap around in the display.
  38.  
  39. click in the memo area and take note of the forms Caption.
  40.                                            
  41.  
« Last Edit: January 13, 2019, 08:47:34 pm by jamie »
The only true wisdom is knowing you know nothing

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Extracting whole string(paragraph) from TMemo and TRichmemo
« Reply #6 on: January 13, 2019, 09:35:15 pm »
If you Compress the Client window so that line wrapping occurs the end of line 1 ends up being line2
[...]

Have you tried indexing the lines by compressing the client window with no scrollbars?
[...]

You need to force a line wrap to see this effect.
if this is behaving differently in other widgets then its not compatible in behavior...
Now do you understand what I am talking about ?

I understood from the first. What I'm telling you, as shown in my first post and attached images, is that it doesn't behave that way--at least not in Linux-i386-GTK2 and, AFAIR, neither have I seen this behaviour in Windows (XP). But I can't test ATM on the Windows machines so maybe it's widgetset-specific behaviour.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

egsuh

  • Hero Member
  • *****
  • Posts: 1273
Re: Extracting whole string(paragraph) from TMemo and TRichmemo
« Reply #7 on: January 14, 2019, 06:57:08 am »
@jamie,

Thank you for your advice and code. I have given some thought to this issue, and found out that the thing to notice is that Memo.Text <> Memo.Lines.Text. So your codes try to get the position of cursor within Memo.Text, and extract the whole string from it.
As I do not want to use SendMessage, etc. (just because I do not have enough knowledge on them), I rewrote the procedure as follows. The SelStart seems to return the position of Cursor if no text is selected.

The point is finding out which line the "SelStart" is located at within Memo.Text. 

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button12Click(Sender: TObject);
  2. var
  3.    i, Index, N : Integer;
  4.    MemoContent : TStringList;
  5. begin
  6.    Index := memo1.SelStart;
  7.    if Index > Length(memo1.Text) then Exit;
  8.  
  9.    N := 0;
  10.    for i := 0 to index do if memo1.Text[i] = #13 then N += 1;
  11.  
  12.    MemoContent := TStringList.Create;
  13.    try
  14.      MemoContent.Text := Memo1.Lines.Text;
  15.      Showmessage(MemoContent[N]);
  16.  
  17.    finally
  18.      MemoContent.Free;
  19.    end;
  20. end;                  
  21.  

This works fine as long as I use single byte characters. Now I'd like to use Korean characters.  It looks like..

가나다

I'm not sure how this will be seen on  your Windows (or Linix).  This is three-character string so SelStart positions would be 0, 1, or 2.
But function Length('가나다') returns 9.

Is there any way that I can find the positions like,

Code: Pascal  [Select][+][-]
  1.   for position := 0 to maxposition (memo1.text) do
  2.     if memo1.text[position] = #13 then N+=1;
  3.  

Hope that you understand what I mean.

BTW, what is the consistent character to line break? #10 or #13?

egsuh

  • Hero Member
  • *****
  • Posts: 1273
Re: Extracting whole string(paragraph) from TMemo and TRichmemo
« Reply #8 on: January 14, 2019, 08:54:43 am »
My final solution is following codes:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button12Click(Sender: TObject);
  2. var
  3.    i, Index, N : Integer;
  4.    MemoContent : TStringList;
  5.    s: string;
  6. begin
  7.    Index := memo1.SelStart;
  8.    memo1.SelStart := 0;
  9.    memo1.SelLength := Index;
  10.    s := memo1.SelText;
  11.  
  12.    N := 0;
  13.    for i := 0 to Length(s)-1 do if s[i] = #13 then N += 1;
  14.  
  15.    MemoContent := TStringList.Create;
  16.    try
  17.       MemoContent.Text := Memo1.Lines.Text;
  18.       if N < MemoContent.Count then Showmessage(MemoContent[N]);
  19.    finally
  20.       MemoContent.Free;
  21.    end;
  22. end;              

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Extracting whole string(paragraph) from TMemo and TRichmemo
« Reply #9 on: January 15, 2019, 12:17:41 am »
yes that will work too, since TEXT is one long contiguous string with CR between lines..

Happy camping.
The only true wisdom is knowing you know nothing

 

TinyPortal © 2005-2018