Lazarus

Programming => General => Topic started by: laznewb on February 16, 2020, 09:22:49 pm

Title: [SOLVED]RichMemo StringReplace?
Post by: laznewb on February 16, 2020, 09:22:49 pm
I'm trying to replace a string in RichMemo. I found the StringReplace function in the freepascal.org docs, but I'm struggling to implement it for some reason. Here is my code:

Code: Pascal  [Select][+][-]
  1. RichMemo1.Lines.Text := StringReplace(RichMemo1.Lines.Text, 'String to replace', 'Orange', [rfReplaceAll]);

I get no errors, it just doesn't do anything. Does anyone know what's wrong?
Title: Re: RichMemo StringReplace?
Post by: winni on February 16, 2020, 09:38:25 pm
Hi!

'String to replace' is not contained in your RichMemo1.Lines.Text.

Winni
Title: Re: RichMemo StringReplace?
Post by: laznewb on February 16, 2020, 09:45:20 pm
Hi!

'String to replace' is not contained in your RichMemo1.Lines.Text.

Winni
I double checked it and made sure that it was, and it was, but then I moved it to a different procedure (instead of FormCreate), and now it works. Do you know how I can keep the formatting of the other text in the RichMemo?
Title: Re: RichMemo StringReplace?
Post by: winni on February 16, 2020, 10:10:00 pm
Hi!

FormCreate exists to iniialize your component - not to execute some cod that relies that everything is already initialized.

What do you want to do? More find and replace?

Put a Button on Form1 for find/replace.

Create a small second Form with one Edit for search and another for replace.
Put a Button on the second from with find/replace.

Then do your stringreplace.

Winni
Title: Re: RichMemo StringReplace?
Post by: Bart on February 16, 2020, 10:59:24 pm
Put a Button on Form1 for find/replace.

Create a small second Form with one Edit for search and another for replace.
Put a Button on the second from with find/replace.

Why are you re-inventing TReplaceDialog?

Bart
Title: Re: RichMemo StringReplace?
Post by: winni on February 16, 2020, 11:17:41 pm
Hi!

Yes Bart, you are right .

But re-inventing makes a lot of fun ....

Winni
Title: Re: RichMemo StringReplace?
Post by: laznewb on February 17, 2020, 12:02:30 am
What do you want to do? More find and replace?
The StringReplace works now, but it removes all existing Rtf formatting in the RichMemo. I was wondering if there is a way to preserve this formatting, and Replace the string with the same font as the string that is being replaced? Thanks.
Title: Re: RichMemo StringReplace?
Post by: winni on February 17, 2020, 12:33:04 am
Hi!

As I see you want realy to work with RichMemo.

As Bart said: We don't want to invent the wheel again.

Here are two pages with a lot of information:

wiki.freepascal.org/RichMemo#TRichMemo (http://wiki.freepascal.org/RichMemo#TRichMemo)

https://wiki.freepascal.org/RichMemo/WorkArounds (https://wiki.freepascal.org/RichMemo/WorkArounds)

Keep on hacking!

Winni
Title: Re: RichMemo StringReplace?
Post by: jamie on February 17, 2020, 02:31:02 am
So I have a question about the TReplaceDialog , since I've never used it. I just checked it and it gives you a option to search entire file ? How do you specify a file path\name ?

  I think that is a little misleading wouldn't you say ?
Title: Re: RichMemo StringReplace?
Post by: dbannon on February 17, 2020, 03:38:52 am
The StringReplace works now, but it removes all existing Rtf formatting in the RichMemo. I was wondering if there is a way to preserve this formatting, and Replace the string with the same font as the string that is being replaced? Thanks.
StringReplace does what it says, it replaces the string. But it does not know anything about the formatting that RichMemo would like to apply to the text in the string.

You probably need to look what that formatting is, change your string and then apply that formatting to the newly inserted string. Gets messy of course if the string you are replacing is not all the same format.

Rich memo has functions for you to read the formatting and reapply it. Just be aware that not everything works on all platforms.

Davo
Title: Re: RichMemo StringReplace?
Post by: lucamar on February 17, 2020, 10:44:48 am
So I have a question about the TReplaceDialog , since I've never used it. I just checked it and it gives you a option to search entire file ? How do you specify a file path\name ?

  I think that is a little misleading wouldn't you say ?

Not really: What that check usually means is whether you want to replace starting at the current caret position or from the beginning (or end, if backwards) of the text. Or, sometimes, search only in the selection versus the whole text. So yeah, maybe it's a little misleading ;)

Frankly, I like better how the Lazarus dialog is built: it says clearly "Origin: From cursor / From beginning" and has an option for "Scope: Selection / Global". Kudos to whoever designed it :)
Title: Re: RichMemo StringReplace?
Post by: laznewb on February 17, 2020, 06:31:30 pm
Thank you for replies everyone. I think I found a solution, but I don't know how to implement it. See, what makes my problem possibly a lot simpler is that the RichMemo contents is read-only, it's contents do not change, except for the one string that I am trying to insert into the RichMemo - and the position this string is to be inserted at remains constant too.

I found the InsertStyledText procedure on the RichMemo wiki page:

Code: Pascal  [Select][+][-]
  1. procedure InsertStyledText(
  2.   const ARichMemo: TCustomRichMemo;
  3.   const TextUTF8: String;
  4.   AStyle: TFontStyles;
  5.   InsPos : Integer = -1 )

How do I implement this procedure? I tried this:

Code: Pascal  [Select][+][-]
  1. procedure InsertStyledText(
  2.   const ARichMemo: TCustomRichMemo;
  3.   const TextUTF8: String;
  4.   AStyle: TFontStyles;
  5.   InsPos : Integer = -1 );
  6. begin
  7. end;  
  8.  
  9. procedure TForm1.Button1(Sender: TObject);
  10. begin
  11.   InsertStyledText(RichMemo1, 'hello', [fsBold], 32);
  12. end;

This doesn't do anything though. But I want 'hello' the be inserted at position 32.

I know how to work with functions, but I have no idea what to do with this procedure - it's not part of RichMemo.

Thanks.
Title: Re: RichMemo StringReplace?
Post by: skalogryz on February 17, 2020, 06:48:13 pm
what os?
Title: Re: RichMemo StringReplace?
Post by: laznewb on February 17, 2020, 07:21:29 pm
what os?
I'm on Windows 10. Thanks for testing it on your end - did you do your procedure the same as me? In the background there, it looks like you haven't declared the InsertStyledText procedure, but it might just be out of view.
THANKS!
Title: Re: RichMemo StringReplace?
Post by: skalogryz on February 17, 2020, 09:08:10 pm
it looks like you haven't declared the InsertStyledText procedure, but it might just be out of view.
you don't need to declare the procedure. It's declared and implemented in richmemoutils.
all you need is to add the unit to the uses section
Code: Pascal  [Select][+][-]
  1. uses
  2.   Classes, SysUtils, ..., Dialogs, RichMemo, RichMemoUtils;
Title: Re: RichMemo StringReplace?
Post by: laznewb on February 17, 2020, 10:21:46 pm
it looks like you haven't declared the InsertStyledText procedure, but it might just be out of view.
you don't need to declare the procedure. It's declared and implemented in richmemoutils.
all you need is to add the unit to the uses section
Code: Pascal  [Select][+][-]
  1. uses
  2.   Classes, SysUtils, ..., Dialogs, RichMemo, RichMemoUtils;
Thank you very much, I missed out the RichMemoUtils unit - it's working perfectly now.

Hi!

FormCreate exists to iniialize your component - not to execute some cod that relies that everything is already initialized.
I've always used FormCreate to execute code in pretty much the same manner before, this is the first time it has not worked - what other procedure can I use to execute code as soon as the form (and it's components) have initialized?

Thanks all.
Title: Re: RichMemo StringReplace?
Post by: Hartmut on February 18, 2020, 09:56:31 am
I've always used FormCreate to execute code in pretty much the same manner before, this is the first time it has not worked - what other procedure can I use to execute code as soon as the form (and it's components) have initialized?

You can use FormActivate() for that. Look in https://lazarus-ccr.sourceforge.io/docs/lcl/forms/tcustomform.onactivate.html
Quote
This handler is called when the form receives focus for the first time at application start up and then subsequently each time focus is changed from another window of the same application to this window.
For focus changes between different applications the Application.OnActivate handler is called instead.
So be carefull, that FormActivate() can be called more then once. If I have code there, that should be executed only once, I use a local typed const for that:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormActivate(Sender: TObject);  
  2.    const first: boolean = true;
  3.    begin
  4.    if first then
  5.       begin
  6.       ...
  7.       first:=false;
  8.       end;
  9.  
  10.    ...
  11.    end;
  12.  
Title: Re: RichMemo StringReplace?
Post by: laznewb on February 18, 2020, 11:13:12 am
Thank you, I did see that on the wiki, but I didn't know how to only call something once only - thanks very much for the example.
Title: Re: RichMemo StringReplace?
Post by: lucamar on February 18, 2020, 01:45:19 pm
Thank you, I did see that on the wiki, but I didn't know how to only call something once only [...]

If everything in the OnActivate handler is only to execute just once this is a (IMHO) better way:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormActivate(Sender: TObject);  
  2. begin
  3.   OnActivate := Nil; {So it's never called again}
  4.   { ... do whatever else ... }
  5. end;
Title: Re: RichMemo StringReplace?
Post by: dbannon on February 18, 2020, 11:38:09 pm
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormActivate(Sender: TObject);  
  2. begin
  3.   OnActivate := Nil; {So it's never called again}
  4.   { ... do whatever else ... }
  5. end;
Wow, neat trick !

What happened to the wiki page we talked about listing clever tricks like this ?

Davo
Title: Re: RichMemo StringReplace?
Post by: lucamar on February 19, 2020, 12:57:23 am
Wow, neat trick !

 :D

Here is another one. There is a little gem in TCustomForm that allows you to set a handler for the first, an only the first OnShow event fired. It's used like this:

Code: Pascal  [Select][+][-]
  1. interface
  2.  
  3. type
  4.   TMainForm = class(TForm)
  5.     {... normal declarations ...}
  6.   public
  7.     procedure FormCreate(Sender: TObject);
  8.     procedure FirstShow(Sender: TObject);
  9.   end;
  10.  
  11. {... etc ...}
  12.  
  13. implementation
  14.  
  15. procedure TMainForm.FormCreate(Sender: TObject);
  16. begin
  17.   AddHandlerFirstShow(FirstShow, True);
  18.   {There is a corresponding RemoveHandlerFirstShow}
  19. end;
  20.  
  21. procedure TMainForm.FirstShow(Sender: TObject);
  22. begin
  23.   {Do whatever the very first time the form is shown and only then.}
  24. end;

Seems as if there should be a related OnFirstShow event but for some reason it isn't there; this technique allows you to mimic its working.

What happened to the wiki page we talked about listing clever tricks like this ?

Dunno. I don't remember having ever talked about it. :-[
Sound like a good idea though it would need quite some maintenance.
Title: Re: RichMemo StringReplace?
Post by: dbannon on February 19, 2020, 11:30:12 pm
What happened to the wiki page we talked about listing clever tricks like this ?

Dunno. I don't remember having ever talked about it. :-[
Sound like a good idea though it would need quite some maintenance.

It was Handoko's idea, I was using the "collective we" !
https://forum.lazarus.freepascal.org/index.php/topic,48264.msg347466.html#msg347466

But great example !
Title: Re: RichMemo StringReplace?
Post by: ReinaldoDuvida on April 22, 2024, 08:24:18 pm
What do you want to do? More find and replace?
The StringReplace works now, but it removes all existing Rtf formatting in the RichMemo. I was wondering if there is a way to preserve this formatting, and Replace the string with the same font as the string that is being replaced? Thanks.

I discovered a way to use StringReplace without losing RichMemo's previous formatting. First I convert the scanned text with its formatting to a StringStream and place this stream value in a Memo. Then I will use StringReplace on the Memo text. Then I converted the memo text to a StringStream and made RichMemo read this StringStream.

Converting RichMemo text to a StringStream and placing the stream value in the Memo:
Code: Pascal  [Select][+][-]
  1. procedure TfRichTextDois.GetStream;
  2. var
  3.   stStringStream : TStringStream;
  4. begin
  5.   Memo1.Clear;
  6.   stStringStream := TStringStream.Create;
  7.   RichMemo1.SaveRichText(stStringStream);
  8.   Memo1.Lines.Add(stStringStream.DataString);
  9.   FreeAndNil(stStringStream);
  10. end;
  11.  

Using StringReplace in Memo:
Code: Pascal  [Select][+][-]
  1. RichMemo1.Lines.Text := StringReplace(RichMemo1.Lines.Text,
  2.                                                           edt_wordsearch.Text,
  3.                                                           edt_wordreplace.Text,
  4.                                                           [rfReplaceAll]);  
  5.  

Taking the memo value, converting it to a StringStream and making RichMemo read this stream:
Code: Pascal  [Select][+][-]
  1. procedure TfRichTextDois.SetStream;
  2. var
  3.   stStringStream : TStringStream;
  4. begin
  5.   stStringStream := TStringStream.Create;
  6.   stStringStream.WriteString(Memo1.Lines.Text);
  7.   stStringStream.Position := 0;
  8.   RichMemo1.LoadRichText(stStringStream);
  9.   FreeAndNil(stStringStream);
  10. end;    
  11.  

Title: Re: [SOLVED]RichMemo StringReplace?
Post by: KodeZwerg on April 22, 2024, 08:44:40 pm
As an alternate, nobody has thought about, simply use the RichMemo api to solve that problem like I have shown here (https://forum.lazarus.freepascal.org/index.php/topic,66917.msg513847.html#msg513847).
Since I was in hurry while posting it, it might need adjustments to properly work.
TinyPortal © 2005-2018