![]() |
Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo zusammen,
ich suche schon längere Zeit nach einer Möglichkeit ein Suchergebnis in der Komponente TSynMemo farblich zu hinterlegen. In einem RichEdit mache ich das ganze mit PosEx und setze dann entsprechend die Attribute. Nur wie mache ich das in einem TSynMemo ? |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo,
ich bin leider immer noch nicht weitergekommen. Hat denn wirklich keiner eine Idee, wie ich es machen kann ? |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo Rolf,
eine Möglichkeit wäre es, die Fundstellen in der Behandlungsroutine für das Ereignis OnPaintTransient einzufärben:
Delphi-Quellcode:
Der Code zeigt nur die ungefähre Vorgehensweise. Beim Suchen wird auf exakte Groß-/Kleinschreibung geachtet, und ein Suchbegriff darf sich nicht über mehrere Zeilen erstrecken.
procedure TForm1.EditorPaintTransient (Sender: TObject; Canvas: TCanvas; TransientType: TTransientType);
const KEY = 'Suchbegriff'; var i, k: Integer; s: string; DP: TDisplayCoord; P: TPoint; begin for i := Editor.TopLine to Editor.TopLine + Editor.LinesInWindow do begin s := Editor.Lines[i - 1]; k := Pos(KEY, s); while (k > 0) do begin DP := Editor.BufferToDisplayPos({SynEditTypes.}BufferCoord(k, i)); P := Editor.RowColumnToPixels(DP); Canvas.Brush.Color := clYellow; Canvas.Font.Color := clRed; Canvas.TextOut (P.X, P.Y, KEY); k := PosEx(KEY, s, k + Length(KEY)); end; end; end; Gruß Hawkeye |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo Hawkeye,
danke für das Code-Beispiel, ich habe jetzt dank Deinem Code eine für mich passende Lösung gefunden, die zu funktionieren scheint. Ich werde das ganze noch ein wenig austesten. |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Gibt es bei TSynEdit/Memo nicht die abstakte Such-Klasse? Zudem schon fertige Suchkomponenten, die man einem SynMemo einfach zuweisen kann bzw. als Vorlage verwenden kann für eigene Suchmethoden.
|
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Meinst Du TSynEditRegexSearch zum Beispiel ?
|
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Also die fertige Komponente, die ich verwendet hab' (aus der Distribution von TSynEdit), liegt in der Unit SynEditSearch und ist von TSynEditSearchCustom abgeleitet.
TSynEditRegexSearch könnte eine weitere abgeleitete Klasse von TSynEditSearchCustom sein (grad' zu faul in den Sourcen zu schauen ;) ). |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Ok, ich verstehe nur noch nicht ganz wie mir das weiterhelfen soll. Ich möchte ja eine farbliche Hinterlegung von bestimmten Wörtern, die ich vorgebe. Das können ja Zeichenketten sein oder auch einzelne Wörter die im genutzen Highlighter hinterlegt sind oder nicht.
Deshalb ist der Sourcecode, so wie Ihn Hawkeye gepostet hat, genau der richtige Ansatz für mein Vorhaben. Wenn Du einen anderen Vorschlag noch hast, nur her damit. |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hmm, dachte es geht einfach darum eine Suche zu implementieren, wie man es halt von Texteditoren so kennt. Also Implementierung einer Suche und Markierung des gefundenen Textes mit den vorhandenen Methoden. Da wäre das dann so gegangen:
Delphi-Quellcode:
TSynEditSearch und TSynEditRegexSearch sind bereits voll funktionsfähig. Da aber als Source vorhanden, leicht anpassbar bzw. von der Basis-Customklasse eigene Engines ableitbar.
uses
SynEdit, SynMemo, SynEditSearch oder SynEditRegexSearch; // Deklaration im Formular SearchEngine : TSynEditSearch; oder SearchEngine : TSynEditRegexSearch procedure TForm1.FormCreate(Sender: TObject); begin SearchEngine := TSynEditSearch.Create(self); SynMemo1.SearchEngine := SearchEngine; // Aufruf erfolgt so SynMemo1.SearchReplace('Suchbegriff oder Expr', '', []); Völlig freies farbliches hinterlegen beliebiger Begriffe ist das dann natürlich nicht. |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo,
vielleicht kann man die beiden Ansätze kombinieren. Wenn ich das richtig sehe, erlaubt TSynEditSearch das Suchen aller Vorkommen eines Suchbegriffs mittels FindAll. Die Anzahl der Fundstellen wird als Funktionsergebnis geliefert, die Positionen sind über TSynEditSearch.GetResult abrufbar. Mit diesen Informationen kann anschließend das Highlighting wie oben beschrieben durchgeführt werden. So könnte man auch ohne Berücksichtigung der Groß-/Kleinschreibung und mit Hilfe von regulären Ausdrücken nach Begriffen im Text suchen. Wohlgemerkt - getestet habe ich das nicht. Es handelt sich hier nur um Folgerungen aus dem Studieren des Quelltextes von TSynEditSearch. Gruß Hawkeye |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo Hawkeye, Hallo Satty67,
das wäre natürlich noch eine Idee, die beiden Ansätze zu kombinieren. Ich werde es mal ausprobieren, da ich es ja für eine Suche gebrauche. |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo zusammen, die Funktion von Hawkeye funktioniert jetzt bestens. Ich habe Sie für mein Programm angepasst. Um mit den normalen SearchEngines für SynMemo zu arbeiten, habe ich noch keine Möglichkeit gefunden. Aber ich habe das Problem mit der Groß- und Kleinschreibung so gelöst, dass ich im Vergleich alles auf UpperCase stelle. Jetzt bleibt lediglich nur noch die Frage, wie ich die Schriftart des Wortes erkennen kann um diese dann mit Canvas entsprechend zeichnen zu können. Denn jetzt ist es so, dass bei Kommentaren das hinterlegte Word von kursiv in normal gestellt wird.
|
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo,
auch wenn Du schon eine Lösung hast, habe es für mich so gelöst:
Delphi-Quellcode:
Nachteil dieser Lösung: Beim Blättern im Memo gehen die Hervorhebungen verloren.
procedure TForm1.Button1Click(Sender: TObject);
Var i: Integer; P: TPoint; begin With SynMemo1 Do Begin SearchEngine := TSynEditSearch.Create(self); SearchEngine.Pattern := InputBox('Suchbegriff','Was sollen wir suchen?',''); SearchEngine.Options := [ssoReplace, ssoReplaceAll]; SearchEngine.FindAll(Text); For i := 0 To SearchEngine.ResultCount - 1 Do begin Canvas.Brush.Color := clYellow; Canvas.Font := Font; Canvas.Font.Color := clRed; P := RowColumnToPixels(BufferToDisplayPos(CharIndexToRowCol(SearchEngine.Results[i] - 1))); Canvas.TextOut(P.X, P.Y, SearchEngine.Pattern); end; end; end; Ansonsten schau Dir mal den PyScripter an, der ist mit den SynEdit-Komponenten geschrieben und hat das von Dir gewünschte Feature. Du bekommst die Quelltexte dazu über ![]() ![]() ![]() |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Zitat:
Delphi-Quellcode:
Wo wird Font defniert und befüllt ? Könnte das eventuell ein Tippfehler sein oder hast Du etwas vergessen ?
Canvas.Font := Font;
|
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo,
Zitat:
Der PyScripter macht das so, wie Du es möchtest, habe aber keine Zeit, da jetzt zu forschen, wie die das genau machen, es sind jedenfalls mehrere Units, die dazu gebraucht werden. Da der Quelltext aber verfügbar ist, sollte es möglich sein, eine analoge Lösung für Dein Programm zu finden. |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
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:
Das Frame, das die Syneditkomponente enthält hat folgende Änderungen erfahren:
type
TFoundItem = class Result : Integer; end;
Delphi-Quellcode:
Die Prozedure SynEditPaint wird dem OnPaint-Ereignis des SynEdits zugewiesen.
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;
Delphi-Quellcode:
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.
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;
Delphi-Quellcode:
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).
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; Die Routine für die Suche sieht folgendermaßen aus:
Delphi-Quellcode:
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.
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; Hoffe, dass das ein bisserl weiterhilft. |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Wie wärs wenn Du einen TSynGeneralSyn als Highlighter nimmst und dort den Suchtext unter "Keywords" hinzufügst? Den Stil wie das gezeichnet werden soll kannst Du ja auch direkt festlegen dort :)
Also zumindest für eine einfache Texte ohne RegEx müsste das gehen. |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo David,
Zitat:
Gruß Hawkeye |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo,
da gibt es nochwas zu bedenken: Wenn ich bereits einen Highlighter zugewiesen habe und den nun durch einen TSynGeneralSyn ersetzte, dann habe ich zwar die Hervorhebung für die Suchbegriffe, aber die eigentliche Hervorhebung geht verloren, bzw. wird durch die des TSynGeneralSyn ersetzt. Eigentlich müsste man den Vorfahren TSynCustomHighlighter anpassen, dann haben alle Highlighter diese Funktionalität. Vermutlich ist der Aufwand noch nicht einmal so riesig. Dazu fällt mir dann die Frage ein: Wie bekommt man heraus, welcher SynEdit...-Komponente ein Highlighter zugewiesen ist (in der Form, dass eine Methode des Highlighters diese Zugehörigkeit ermittelt)? |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo,
ein paar Stunden später: Es geht viel einfacher: Wir brauchen eine Routine, die uns nach dem Suchbegriff fragt:
Delphi-Quellcode:
Das OnPaint-Ereignis des SynEdit bekommt folgende Routine:
// Der über die InputBox eingegebene Text wird im SynEdit hervorgehoben.
procedure TfmMain.acFindAndMarkExecute(Sender: TObject); begin with ActiveFrameEditor.SynEdit Do begin If Not Assigned(SearchEngine) then begin SearchEngine := TSynEditSearch.Create(ActiveFrameEditor.SynEdit); SearchEngine.Options := [ssoReplace, ssoReplaceAll]; end; SearchEngine.Pattern := ''; Repaint; // Damit alte Markierungen entfernt werden. SearchEngine.Pattern := InputBox('Eingabe','Suchbegriff',''); Repaint; // Damit neue Markierungen gesetzt werden, einmal neu zeichnen. end; end;
Delphi-Quellcode:
Bei Änderungen im SynEdit machen wir folgendes:
procedure TFrameEditor.SynEditPaint(Sender: TObject; ACanvas: TCanvas);
var i : Integer; j : Integer; P : TPoint; begin with SynEdit do begin // Ist keine Suchmaschine zugewiesen, raus, dann können wir uns das sparen. If Not Assigned(SearchEngine) then Exit; If SearchEngine.Pattern = '' then Exit; ACanvas.Font := Font; // Font des SynEdits, sonst stimmt der Schrifttyp nicht. ACanvas.Brush.Color := clYellow; ACanvas.Brush.Style := bsSolid; // Die Suchbegriffe werden nur im sichtbaren Bereich hervorgehoben, // spart bei großen Dateien viel Zeit. for i := TopLine - 1 to TopLine + LinesInWindow do begin SearchEngine.FindAll(Lines[i]); for j := 0 to SearchEngine.ResultCount - 1 do begin P := RowColumnToPixels(BufferToDisplayPos(BufferCoord(SearchEngine.Results[j], i + 1))); ACanvas.TextOut(P.X, P.Y, SearchEngine.Pattern); end; end; end; end;
Delphi-Quellcode:
Das führt dazu, dass Hervorhebungen erhalten bleiben, während man Text eingibt oder löscht...
procedure TFrameEditor.SynEditChange(Sender: TObject);
begin SynEdit.Repaint; // Markierungen neu zeichnen end; |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo,
Zitat:
Delphi-Quellcode:
procedure TFrameEditor.SynEditPaint(Sender: TObject; ACanvas: TCanvas);
var i : Integer; j : Integer; P : TPoint; Token : String; Attri : TSynHighlighterAttributes; begin with SynEdit do begin // Ist keine Suchmaschine zugewiesen, raus, dann können wir uns das sparen. If Not Assigned(SearchEngine) then Exit; If SearchEngine.Pattern = '' then Exit; ACanvas.Brush.Color := clYellow; ACanvas.Brush.Style := bsSolid; // Die Suchbegriffe werden nur im sichtbaren Bereich hervorgehoben, // spart bei großen Dateien viel Zeit. for i := TopLine - 1 to TopLine + LinesInWindow do begin SearchEngine.FindAll(Lines[i]); for j := 0 to SearchEngine.ResultCount - 1 do begin P := RowColumnToPixels(BufferToDisplayPos(BufferCoord(SearchEngine.Results[j], i + 1))); GetHighlighterAttriAtRowCol(BufferCoord(SearchEngine.Results[j], i + 1),Token,Attri); Try ACanvas.Font.Style := Attri.Style; except on e : Exception do ACanvas.Font := Font; end; ACanvas.TextOut(P.X, P.Y, SearchEngine.Pattern); end; end; end; end; |
Re: Suchergbenisse farblich hinterlegen (TSynMemo)
Hallo Stephan,
erstmal ein ganz dickes Lob für Deine Arbeit. :thumb: Ich habe viel aus Deinen geposteten Beispielen gelernt. Danke. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:50 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz