A Delphiprog : ReplaceDialog sur un RichEdit

Résolu
cs_Jean-Pierre Messages postés 82 Date d'inscription jeudi 25 septembre 2003 Statut Membre Dernière intervention 20 avril 2010 - 23 nov. 2004 à 20:56
cs_Jean-Pierre Messages postés 82 Date d'inscription jeudi 25 septembre 2003 Statut Membre Dernière intervention 20 avril 2010 - 27 nov. 2004 à 23:11
Bonjour,

Encore merci du code ci-dessous que tu as eu la gentillesse de réaliser l'autre fois.

Il fonctionne impec avec un Memo.

Or là, je viens de voir que si je remplace le Memo par un RichEdit, si jamais un texte assez long existe, ça pédale un max lors d'un simple "Remplacer".

A plusieurs reprises en comparant le fonctionnenemnt entre un Memo et un RichEdit = il est certain que c'est bien le RichEdit qui fait pédaler le code.

Ma question si j'ose abuser est : comment trouver une parade pour éviter cela ?

Merci d'avance ;o)


unit UReplaceDemoMain;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, ComCtrls, StrUtils;

type
TReplaceDemoMainForm = class(TForm)
ReplaceDialog1: TReplaceDialog;
Memo1: TMemo;
btnSearch: TButton;
Panel1: TPanel;
Panel2: TPanel;
procedure btnSearchClick(Sender: TObject);
procedure ReplaceDialog1Replace(Sender: TObject);
procedure ReplaceDialog1Find(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{Recherche l'occurence suivante de FindNext dans Memo et déplace la sélection. }
procedure GotoNext(Memo: TCustomMemo; OldText: string; Options: TFindOptions);
end;

var
ReplaceDemoMainForm: TReplaceDemoMainForm;

implementation

{$R *.dfm}

procedure TReplaceDemoMainForm.btnSearchClick(Sender: TObject);
begin
//La sélection est supposée être le texte à rechercher
if Memo1.SelLength > 0 then
ReplaceDialog1.FindText := Memo1.SelText;
ReplaceDialog1.Execute;
end;

procedure TReplaceDemoMainForm.ReplaceDialog1Replace(Sender: TObject);
var
ReplaceFlags: TReplaceFlags;
begin
ReplaceFlags := [];
with Sender as TReplaceDialog do
begin
//Clic sur le bouton "Remplacer"
if frReplace in Options then
begin
if not (frMatchCase in Options) then
include(ReplaceFlags, rfIgnoreCase);
StringReplace(Memo1.Lines.Text, FindText, ReplaceText, ReplaceFlags);
exit;
end;

//Clic sur le bouton "Tout remplacer"
if frReplaceAll in Options then
begin
//Remplacer toutes les occurences
if frMatchCase in Options then
Memo1.Lines.Text := AnsiReplaceStr(Memo1.Lines.Text, FindText, ReplaceText)
else
Memo1.Lines.Text := AnsiReplaceText(Memo1.Lines.Text, FindText, ReplaceText);
exit;
end;
end;
end;

procedure TReplaceDemoMainForm.ReplaceDialog1Find(Sender: TObject);
begin
with ReplaceDialog1 do
//Rechercher l'occurence suivante ?
if frFindNext in Options then
GotoNext(Memo1, FindText, Options);
end;

procedure TReplaceDemoMainForm.FormCreate(Sender: TObject);
begin
Memo1.Lines.LoadFromFile('UReplaceDemoMain.pas');
end;

procedure TReplaceDemoMainForm.GotoNext(Memo: TCustomMemo;
OldText: string; Options: TFindOptions);
var
{ Position de départ de la sélection }
SelPos: integer;
{ Sous-texte servant à la
recherche de l'occurence suivante }
SubText: string;
{ Position de départ pour une recherche du suivant }
StartPos: integer;
const
Alpha = ['a'..'z', 'A'..'Z'];
begin
//déterminer le point de départ de la recherche
StartPos := Memo.SelStart + Memo.SelLength + 1;
//Rechercher dans le texte à partir du texte qui suit la sélection
//ou dans tout le texte si aucune sélection
SubText := Copy(Memo.Lines.Text, StartPos, Length(Memo.Lines.Text));
//Faut-il tenir compte de la casse ?
if frMatchCase in Options then
SelPos := AnsiPos(OldText, SubText)
else
SelPos := AnsiPos(LowerCase(OldText), LowerCase(SubText));

//Rechercher des mots entiers ?
if frWholeWord in Options then
if SelPos > 1 then
{Vérifier que le caractère qui précéde ou celui qui suit
n'est pas un caractère alphabétique}
if (SubText[SelPos - 1] in Alpha)
or (SubText[SelPos + Length(OldText)] in Alpha) then
begin
{Positionner la sélection après le mot trouvé}
Memo.SelStart := StartPos + Length(OldText);
Memo.SetFocus;
Exit;
end;

if SelPos > 0 then
begin
Memo.SelStart := StartPos + SelPos - 2;
Memo.SelLength := Length(OldText);
Memo.SetFocus;
end
else
ShowMessageFmt('"%s" non trouvé ou la ' + sLineBreak
+ 'fin du texte a été atteinte', [OldText]);
end;

end.

7 réponses

cs_Jean-Pierre Messages postés 82 Date d'inscription jeudi 25 septembre 2003 Statut Membre Dernière intervention 20 avril 2010
26 nov. 2004 à 17:03
Bonjour,

Philippe, je pense avoir cerné le problème, enfin il suffit de virer tous les "LINES" des :

"RichEdit1.Lines.Text" et ça semble fonctionner impec jusque là !

Mais je me demande bien l'explication finale du "pourquoi", ça me paraît trop beau ?
(Je suis débutant)

Merci d'avance de tes précieux conseils.

Je parle exclusivement de la procédure suivante qui faisait "pédaler le curseur":

"avant " ;o( :
 //ReplaceDialog : procédure 3/5 :
procedure TForm1.ReplaceDialog1Replace(Sender: TObject);
    var
      ReplaceFlags: TReplaceFlags;
      BeforeSelText, FromSelText: string;
      OldSelStart: integer;
    begin
       ReplaceFlags :=  [];
          //Distinguer le texte avant la sélection et celui à partir de
           with RichEdit1 do
        begin
           BeforeSelText := Copy(Lines.Text, 1, SelStart - 1);
           FromSeltext := Copy(Lines.Text, SelStart, Length(Lines.Text));
           //Mémoriser l'emplacement de la sélection qui se trouve perdu après une opération de remplacement
           OldSelStart := SelStart;
         end;
           with Sender as TReplaceDialog do

          begin
              if frReplace in Options then                    {Clic sur le bouton "Remplacer"}
           begin
             if not (frMatchCase in Options) then
              include(ReplaceFlags, rfIgnoreCase);
                                {effectuer le remplacement seulement dans le texte qui suit la sélection}
                RichEdit1.Lines.Text := BeforeSelText + StringReplace(FromSelText, FindText, ReplaceText, ReplaceFlags);
                {repositionnement du point de départ de la sélection}
                RichEdit1.SelStart := OldSelStart;
                  GotoNext(RichEdit1, FindText, Options);
                  exit;
                end;

             begin                                         {Clic sur le bouton "Tout remplacer"}
               if frReplaceAll in Options then
                                                           {Remplacer toutes les occurences}
            if frMatchCase in Options then
               RichEdit1.Lines.Text := AnsiReplaceStr(RichEdit1.Lines.Text, FindText, ReplaceText)
           else
        RichEdit1.Lines.Text := AnsiReplaceText(RichEdit1.Lines.Text, FindText, ReplaceText);
       exit;
     end;
  end;
end;


"après" ;o) ;
  //ReplaceDialog : procédure 3/5 :
procedure TForm1.ReplaceDialog1Replace(Sender: TObject);
    var
      ReplaceFlags: TReplaceFlags;
      BeforeSelText, FromSelText: string;
      OldSelStart: integer;
    begin
       ReplaceFlags : = [];
          //Distinguer le texte avant la sélection et celui à partir de
           with RichEdit1 do
        begin
           BeforeSelText := Copy(Lines.Text, 1, SelStart - 1);    
           FromSeltext := Copy(Lines.Text, SelStart, Length(Lines.Text));
           //Mémoriser l'emplacement de la sélection qui se trouve perdu après une opération de remplacement
           OldSelStart := SelStart;
         end;
           with Sender as TReplaceDialog do

          begin
              if frReplace in Options then                    {Clic sur le bouton "Remplacer"}
           begin
             if not (frMatchCase in Options) then
              include(ReplaceFlags, rfIgnoreCase);
                                {effectuer le remplacement seulement dans le texte qui suit la sélection}
RichEdit1.Text := BeforeSelText + StringReplace(FromSelText, FindText, ReplaceText, ReplaceFlags);
                  {repositionnement du point de départ de la sélection}
                RichEdit1.SelStart := OldSelStart;
                  GotoNext(RichEdit1, FindText, Options);
                  exit;
                end;

             begin                                         {Clic sur le bouton "Tout remplacer"}
               if frReplaceAll in Options then
                                                           {Remplacer toutes les occurences}
            if frMatchCase in Options then
RichEdit1.Text := AnsiReplaceStr(RichEdit1.Text, FindText, ReplaceText)
           else
RichEdit1.Text := AnsiReplaceText(RichEdit1.Text, FindText, ReplaceText);
       exit;
     end;
  end;
end;
3
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
27 nov. 2004 à 19:05
Bonsoir Jean-Pierre,

Je constate une légère différence de rapidité entre les appels à RichEdit1.Text et à RichEdit1.Lines.text au profit du premier.
Mais rien de rédhibitoire.
J'ai pu aussi constater ce qui suit : le résultat obtenu n'est pas le même quand on fait (Memo1 est du type TRichEdit ici) :
ShowMessage(Memo1.Text)

et quand on écrite ceci :
ShowMessage(Memo1.Lines.Text)


Regarde bien le texte qui s'affiche et tu constateras une différence de mise en forme.
L'appel à Memo1.Lines.Text est strictement identique à ce qui est affiché dans un TRichEdit.
L'utilisation de la propriété Text d'un TRichEdit, bien que légèrement plus rapide, pourrait donner des résultats imprévus.
Alors, résultat identique ou résultat plus rapide ?
Cruel dilemne...

Pensez à cliquer sur Réponse acceptée lorsque la réponse vous convient.
May Delphi be with you
3
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
27 nov. 2004 à 21:54
Tant que j'y pense, au départ le code a été écrit pour un TMemo.
Mais puisque tu as opté pour des TRichEdit, tu devrais revoir le code et exploiter les possibilités offertes par la méthode FindText.
L'aide en ligne de delphi fournit un exemple complet et fonctionnel.

PS : quand je parlais de différences, cela se mesurait en centièmes de secondes, pas plus.

PS2 : (on se console comme on peut :big) )
Le composant TRichEdit s'appuie sur la bibliothèque riched20.dll livrée avec Windows. Comme cette bibliothèque a évolué au fil du temps (la mienne porte le n° de version 5.30.23.1221), les différences proviennent surement de là.

Pensez à cliquer sur Réponse acceptée lorsque la réponse vous convient.
May Delphi be with you
3
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
23 nov. 2004 à 22:53
Le remplacement d'un TMemo par un TRichEdit ne doit pas poser de problème. Cette démarche avait d'ailleurs été anticipée puisque la procédure GotoNext reçoit un paramètre de la classe TCustomMemo qui est l'ancêtre commun des deux classes citées.

Dans le code figurant ci-dessus, j'ai donc vérifié en remplaçant le TMemo par un TRichEdit, purement et simplement : le code fonctionne sans problème. A mon avis, mais je peux me tromper, le problème est ailleurs.

May Delphi be with you
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_Jean-Pierre Messages postés 82 Date d'inscription jeudi 25 septembre 2003 Statut Membre Dernière intervention 20 avril 2010
23 nov. 2004 à 23:22
Bonsoir,

Oui je pense aussi que le problème est ailleurs ; certainement ma façon d'avoir modifié le code pour les besoins du changement de ce Memo en RichEdit.

Des bêtises de débutants... ;o)

Je précise que tout se passe OK, sauf si par exemple je place un texte de 50 Ko dans le RichEdit.

Là lors d'un "Remplacer" la flèche du curseur "frétille" au moins une minute.

Enfin j'ai un Windows 98se, mais tout de même.

Voici la totalité du code que j'ai modifié pour cette histoire de Memo échangé contre un RichEdit :

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, StrUtils;

type
  TForm1 = class(TForm)
    ReplaceDialog1: TReplaceDialog;
    btnRemplace: TButton;
    RichEdit1: TRichEdit;

    procedure btnRemplaceClick(Sender: TObject);       //ReplaceDialog
    procedure ReplaceDialog1Replace(Sender: TObject);  //ReplaceDialog
    procedure ReplaceDialog1Find(Sender: TObject);     //ReplaceDialog

  private
    //ReplaceDialog : procédure 1/5 : Recherche l'occurence suivante de FindNext dans Memo et déplace la sélection
    procedure GotoNext(Memo: TCustomMemo; OldText: string; Options: TFindOptions);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

       //ReplaceDialog : Procédure 2/5
procedure TForm1.btnRemplaceClick(Sender: TObject);
   begin
      //La sélection est supposée être le texte à rechercher
       if RichEdit1.SelLength > 0 then
      ReplaceDialog1.FindText := RichEdit1.SelText;
    ReplaceDialog1.Execute;
end;

         //ReplaceDialog : procédure 3/5 :
procedure TForm1.ReplaceDialog1Replace(Sender: TObject);
    var
      ReplaceFlags: TReplaceFlags;
      BeforeSelText, FromSelText: string;
      OldSelStart: integer;
    begin
       ReplaceFlags := [];
          //Distinguer le texte avant la sélection et celui à partir de
           with RichEdit1 do
        begin
           BeforeSelText := Copy(Lines.Text, 1, SelStart - 1);
           FromSeltext := Copy(Lines.Text, SelStart, Length(Lines.Text));
           //Mémoriser l'emplacement de la sélection qui se trouve perdu après une opération de remplacement
           OldSelStart := SelStart;
         end;
           with Sender as TReplaceDialog do

          begin
              if frReplace in Options then                    {Clic sur le bouton "Remplacer"}
           begin
             if not (frMatchCase in Options) then
              include(ReplaceFlags, rfIgnoreCase);
                                {effectuer le remplacement seulement dans le texte qui suit la sélection}
                RichEdit1.Lines.Text := BeforeSelText + StringReplace(FromSelText, FindText, ReplaceText, ReplaceFlags);
                {repositionnement du point de départ de la sélection}
                RichEdit1.SelStart := OldSelStart;
                  GotoNext(RichEdit1, FindText, Options);
                  exit;
                end;

             begin                                         {Clic sur le bouton "Tout remplacer"}
               if frReplaceAll in Options then
                                                           {Remplacer toutes les occurences}
            if frMatchCase in Options then
               RichEdit1.Lines.Text := AnsiReplaceStr(RichEdit1.Lines.Text, FindText, ReplaceText)
           else
        RichEdit1.Lines.Text := AnsiReplaceText(RichEdit1.Lines.Text, FindText, ReplaceText);
       exit;
     end;
  end;
end;

              //ReplaceDialog : procédure 4/5 :
procedure TForm1.ReplaceDialog1Find(Sender: TObject);
   begin
      with ReplaceDialog1 do
        //Rechercher l'occurence suivante ?
     if frFindNext in Options then
   GotoNext(RichEdit1, FindText, Options);
end;

               //ReplaceDialog : procédure 5/5 :
procedure TForm1.GotoNext(Memo: TCustomMemo; OldText: string; Options: TFindOptions);
  var
     //Position de départ de la sélection
     SelPos: integer;
       //Sous-texte servant à la recherche de l'occurence suivante
       SubText: string;
       //Position de départ pour une recherche du suivant
       StartPos: integer;
     const
      Alpha = ['a'..'z', 'A'..'Z'];
    begin
      //déterminer le point de départ de la recherche
      StartPos := Memo.SelStart + Memo.SelLength + 1;
      //Rechercher dans le texte à partir du texte qui suit la sélection
      //ou dans tout le texte si aucune sélection
       SubText := Copy(Memo.Lines.Text, StartPos, Length(Memo.Lines.Text));
       //Faut-il tenir compte de la casse ?
         if frMatchCase in Options then
           SelPos := AnsiPos(OldText, SubText)
             else
            SelPos := AnsiPos(LowerCase(OldText), LowerCase(SubText));
                                                           //Rechercher des mots entiers ?
          if frWholeWord in Options then
           if SelPos > 1 then
            //Vérifier que le caractère qui précéde ou celui qui suit n'est pas un caractère alphabétique
            if (SubText[SelPos - 1] in Alpha) or (SubText[SelPos + Length(OldText)] in Alpha) then
         begin
             //Positionner la sélection après le mot trouvé
             Memo.SelStart := StartPos + Length(OldText);
          Memo.SetFocus;
        Exit;
      end;
         if SelPos > 0 then
      begin
        Memo.SelStart := StartPos + SelPos - 2;
        Memo.SelLength := Length(OldText);
        Memo.SetFocus;
           end
        else
     begin
      //ShowMessageFmt('"%s" non trouvé ou la ' + sLineBreak + 'fin du texte a été atteinte', [OldText]); ORIGINE
      MessageBeep(MB_ICONASTERISK);
    ShowMessageFmt('"%s" non trouvé ou la fin du texte a été atteinte', [OldText]);
  end;
end;

END.
0
cs_Jean-Pierre Messages postés 82 Date d'inscription jeudi 25 septembre 2003 Statut Membre Dernière intervention 20 avril 2010
27 nov. 2004 à 20:23
Bonsoir à tous, bonsoir Philippe,

Tu disais :
Je constate une légère différence de rapidité entre les appels à RichEdit1.Text et à RichEdit1.Lines.text au profit du premier.
Mais rien de rédhibitoire.
je suis sous Windows 98se avec processeur à 500 Mhz, ceci expliquant peut-être cela.
Par exemple sur un texte de 60 Ko, il faut compter au moins 40 secondes afin d'attendre l'arrêt du virevoltement du curseur sur chaque "Remplacer" ; rien de rédhibitoire dis-tu... ;o)

Mais ceci dit : je te crois sur parole, tu ne dois plus être sous Win 98se.
Perso je refuse XP, enfin... je suis un peu borné là-dessus ;o))

En parallèle et en parenthèse de ce sujet précis dito, l'autre fois j'avais installé StarOffice 5.2 chez un copain ayant un P II = environ deux heures pour installer ce soft !

Tu disais aussi :
J'ai pu aussi constater ce qui suit : le résultat obtenu n'est pas le même quand on fait (Memo1 est du type TRichEdit ici) :

ShowMessage(Memo1.Text)

et quand on écrite ceci :

ShowMessage(Memo1.Lines.Text)
Toujours sous le même OS, sur 5 "captures de textes différentes = rien vu en différence de mise en forme.
Certainement encore des divergeances au niveau de l'interprétation d'OS...

(Qui d'autre peut faire ce test entre XP et 98se ?)

Philippe, je te remercie très sincèrement de toutes tes explications qui me sont ou me seront toujours utiles.

D'ailleurs je viens de terminer de petits ajouts grâce à tes "indications notées" dans les lignes de tes codes.

Il est certain que Windows est un petit canailloux.

Que Delphi and Windows soient avec nous ;o)
0
cs_Jean-Pierre Messages postés 82 Date d'inscription jeudi 25 septembre 2003 Statut Membre Dernière intervention 20 avril 2010
27 nov. 2004 à 23:11
Re,

Oui merci encore Philippe pour ces précieuses infos !

>Le composant TRichEdit s'appuie sur la bibliothèque
> riched20.dll livrée avec Windows. Comme cette
> bibliothèque a évolué au fil du temps (la mienne
>porte le n° de version 5.30.23.1221), les différences
> proviennent surement de là.

Oui en effet, j'avais lu un article sur je ne sais plus quelle application que l'auteur parlait de cette différence notable.

Il me semble même que c'est sur ce forum, quant à un code inhérent à la détection d'hyperliens dans un... TRichEdit
0
Rejoignez-nous