Einzelnen Beitrag anzeigen

nahpets
(Gast)

n/a Beiträge
 
#16

Re: Suchergbenisse farblich hinterlegen (TSynMemo)

  Alt 10. Sep 2009, 10:09
Hallo,

bei meinem Editor klappt das mit der Hervorhebung nun, sie bleibt auch beim Blättern erhalten.

Was habe ich dazu gemacht?

Eine Klasse angelegt:
Delphi-Quellcode:
type
  TFoundItem = class
    Result : Integer;
  end;
Das Frame, das die Syneditkomponente enthält hat folgende Änderungen erfahren:
Delphi-Quellcode:
TFrameEditor = class(TFrame)
  ...
  procedure SynEditPaint(Sender: TObject; ACanvas: TCanvas);
  procedure SynEditChange(Sender: TObject);

  private
  { Private-Deklarationen }
  ...
  fHighlightedTerm : String; // hierin merken wir uns den Suchbegriff für die Hervorhebung.
  fFoundItems: TObjectList; // Liste der Fundstellen.

public
  { Public-Deklarationen }
  ...
  property FoundItems : TObjectList read fFoundItems Write fFoundItems;
  property HighlightedTerm : String read fHighlightedTerm Write fHighlightedTerm;
end;
Die Prozedure SynEditPaint wird dem OnPaint-Ereignis des SynEdits zugewiesen.
Delphi-Quellcode:
procedure TFrameEditor.SynEditPaint(Sender: TObject; ACanvas: TCanvas);
var
  i : Integer;
  FoundItem : TFoundItem;
  P : TPoint;
begin
  with SynEdit do begin
    for i := 0 to fFoundItems.Count - 1 do begin
      FoundItem := fFoundItems[i] as TFoundItem;
      P := RowColumnToPixels(BufferToDisplayPos(CharIndexToRowCol(FoundItem.Result - 1)));
      ACanvas.Font := Font;
      ACanvas.Brush.Color := clYellow;
      ACanvas.Brush.Style := bsSolid;
      ACanvas.TextOut(P.X, P.Y, HighlightedTerm);
    end;
  end;
end;
Bei Änderungen im Editor, werden die Markierungen aufgehoben, da sie ihre Position ändern und daher neu gesucht werden müssten, bevor man sie neu zeichnet. Das ließe sich nur verhindern, wenn man bei jeder Änderung die Suche wiederholt, um die Markierungen an den neuen Stellen zu setzen.
Delphi-Quellcode:
procedure TFrameEditor.SynEditChange(Sender: TObject);
begin
  // Bei Änderungen im Editor die Markierungen aufheben,
  // da ansonsten das Neuzeichnen der Markierung nicht mehr
  // gelingt, da sich die Positionen der markierten
  // Stellen verändern und daher neu gesucht werden müssten.
  If FoundItems.Count > 0 then begin
    FoundItems.Clear;
    SynEdit.Repaint; // Damit alte Markierungen entfernt werden.
  end;
end;
Beim Erstellen des Formulars/Frames darf das Erstellen der Objektliste nicht vergessen werden und bei der Freigabe das Free (was ich immer wieder so mache).

Die Routine für die Suche sieht folgendermaßen aus:
Delphi-Quellcode:
procedure TfmMain.acTestactionExecute(Sender: TObject);
Var
          i : Integer;
          FoundItem : TFoundItem;
begin
  with ActiveFrameEditor.SynEdit Do begin
    // Liste der "alten" Markierungen löschen.
    ActiveFrameEditor.FoundItems.Clear;
    Repaint; // Damit alte Markierungen auch optisch entfernt werden.
    ActiveFrameEditor.HighlightedTerm := InputBox('Eingabe','Suchbegriff','');
    SearchEngine := SynEditSearch;
    SearchEngine.Pattern := ActiveFrameEditor.HighlightedTerm;
    SearchEngine.Options := [ssoReplace, ssoReplaceAll];
    SearchEngine.FindAll(Text);
    for i := 0 to SearchEngine.ResultCount - 1 do begin
      FoundItem := TFoundItem.Create;
      FoundItem.Result := SearchEngine.Results[i];
      ActiveFrameEditor.FoundItems.Add(FoundItem);
    end;
    Repaint; // Damit neue Markierungen gesetzt werden, einmal neu zeichnen.
  end;
end;
Bei der Verwendung von SynEdit.TopLine und SynEdit.LinesInWindow könnte man eventuell durch zeilenweises Suchen und Markieren, die Markierungen auch bei Änderungen aufrechterhalten, das habe ich aber (noch) nicht ausprobiert.

Hoffe, dass das ein bisserl weiterhilft.
  Mit Zitat antworten Zitat