Pulpapex
Einfaches Keyword-Highlighting mit der RichTextBox
Die RichTextBox ist ja im allgemeinen als träge und lahm verschrien. Ich möchte im folgenden zeigen, wie man dennoch schnelles, interaktives Syntax Highlighting hinbekommt. Schlüsselwörter werden bei der Eingabe hervorgehoben.
Die Demo-Anwendung besteht aus vier kleinen Klassen, die ich im folgenden im Detail beschreiben werde:
Zu KeywordHilightingTest gibt es nicht viel zu sagen. Die Klasse enthält nur die Main-Methode:
KeywordHilightingForm
KeywordHilightingForm ist auch sehr einfach. Als einziges Control befindet sich eine RichTextBox mit DockStyle.Fill auf der Form. Für das RichTextBox.TextChanged-Ereignis wurde ein EventHandler eingerichtet. Das Ereignis wird bei jedem Tastendruck ausgelöst und ruft die HilightAtCursor-Methode auf. Desweiteren enthält die Klasse noch ein String-Array mit den Schlüsselwörtern und verfügt über eine KeywordHilighter-Eigenschaft, die das eigentliche Hervorheben übernimmt.
RichTextBoxKeywordHilighter
Die RichTextBoxKeywordHilighter-Klasse ist wie gesagt für das eigentliche Hervorheben zuständig. Der Trick besteht darin, so wenig Text wie nur möglich zu bearbeiten. Deshalb wird auch nur das Wort vor dem Cursor untersucht, das gerade eingegeben wird. Die gesamte Textzeile zu aktualisieren wäre zwar einfacher, dauert aber schon zu lange.
Der Code für die Texthervorhebungen befindet sich in der HilightAt-Methode. Als Parameter wird ein Index auf ein Zeichen übergeben. Der Index darf um 1 grösser sein als die Position des letzten Zeichens im hervorzuhebenden Wort. Er entspricht damit der Cursorposition, wenn das Wort gerade eingegeben wird. Den Code der Methode habe ich hier in mehrere Blöcke aufgeteilt, um ihre Funktion besser beschreiben zu können.
Zunächst einmal wird der Text aus der RichTextBox benötigt. RichTextBox ist eine Eigenschaft von RichTextBoxKeywordHilighter.
Jetzt kann das Wort vor der Cursorposition gesucht werden. Zuerst wird der Wortanfang ermittelt.
Hier der im Code verwendete, reguläre Ausdruck wordStartRegex. Er sucht ausgehend vom Cursor rückwärts:
Ab Wortanfang wird wieder vorwärts nach dem Wortende gesucht.
Hier der zugehörige, reguläre Ausdruck wordEndRegex:
Aus Wortanfang und Wortende wird die Wortlänge ermittelt. Ist sie 0, gibt es nichts zu highlighten und es kann sofort abgebrochen werden:
Wurde ein Wort gefunden, wird überprüft ob es sich um ein Schlüsselwort handelt. Dementsprechend wird eine Textfarbe ausgewählt. KeywordColor ist wieder eine Eigenschaft von RichTextBoxKeywordHilighter.
Nun folgt das eigentliche Hervorheben. Zuvor muss aber noch die aktuelle Selektion der RichTextBox gesichert werden. Sie legt auch die Cursorposition fest, die im Anschluss wieder hergestellt werden muss. Das geschied in den Methoden BeginUpdate und EndUpdate.
Wie man am Code sieht, gibt es einen Sonderfall, der extra behandelt werden muss. Normalerweise wird nur das Wort vor dem Cursor beachtet. Wird jedoch ein Wort durch einen Tastendruck in zwei Wörter aufgetrennt, kann sich auch die Farbe des Wortes hinter dem Cursor ändern. In dem Fall wird HilightAt einfach ein zweites Mal aufgerufen.
Der Code, wie er jetzt ist, funktioniert eigentlich schon zufriedenstellend. Es gibt keine Verzögerungen beim Tippen und gleichzeitigem Highlighting. Allerdings sind die in HilightAt programmatisch vorgenommenen Selektionen für den Benutzer sichtbar. Sie fallen durch kurzes Aufblitzen unangenehm auf. Dieses Problem löst die RichTextBoxUpdater-Klasse. Den Code hierfür habe ich in Pete's Weblog gefunden:
Pete's Weblog:
Extending RichTextBox, Part I
RichTextBoxUpdater
RichTextBoxUpdater definiert zwei Methoden, BeginUpdate und EndUpdate. BeginUpdate deaktiviert die Aktualisierung der RichTextBox-Anzeige während vom Programm Textänderungen vorgenommen werden. EndUpdate reaktiviert die Aktualisierung wieder. Leider gibt es in der RichTextBox-Klasse keine Methoden, die das erledigen. Es muss also wiedermal auf P/Invoke und die Win-Api zurückgegriffen werden.
Die Einzelheiten können auf der angegebenen Seite nachgelesen werden, hier nur noch der Code für die Klasse:
Das war's auch schon. So sieht das Ergebnis aus:

Wenn ihr Lust habt, probiert die angehängte Demo-Anwendung aus. Die Zip-Datei enthält auch den kompletten Quellcode, den ihr nach Belieben zerpflücken und in eigene Anwendungen einbauen könnt. Bei Pete's Code bin ich mir nicht so sicher, aber ich denke, dass eine Quellenangabe ausreichen sollte.
In einem zweiten Teil werde ich die RichTextBoxKeywordHilighter-Klasse nochmal um das Highlighten für Textbereiche erweitern, damit sie auch beim Laden von Textdateien und bei Copy&Paste funktioniert.
Gruss
Pulpapex
Die RichTextBox ist ja im allgemeinen als träge und lahm verschrien. Ich möchte im folgenden zeigen, wie man dennoch schnelles, interaktives Syntax Highlighting hinbekommt. Schlüsselwörter werden bei der Eingabe hervorgehoben.
Die Demo-Anwendung besteht aus vier kleinen Klassen, die ich im folgenden im Detail beschreiben werde:
- KeywordHilightingTest
- KeywordHilightingForm
- RichTextBoxKeywordHilighter
- RichTextBoxUpdater
Zu KeywordHilightingTest gibt es nicht viel zu sagen. Die Klasse enthält nur die Main-Methode:
C#-Code: |
class KeywordHilightingTest {
|
KeywordHilightingForm
KeywordHilightingForm ist auch sehr einfach. Als einziges Control befindet sich eine RichTextBox mit DockStyle.Fill auf der Form. Für das RichTextBox.TextChanged-Ereignis wurde ein EventHandler eingerichtet. Das Ereignis wird bei jedem Tastendruck ausgelöst und ruft die HilightAtCursor-Methode auf. Desweiteren enthält die Klasse noch ein String-Array mit den Schlüsselwörtern und verfügt über eine KeywordHilighter-Eigenschaft, die das eigentliche Hervorheben übernimmt.
C#-Code: |
public class KeywordHilightingForm : Form {
|
RichTextBoxKeywordHilighter
Die RichTextBoxKeywordHilighter-Klasse ist wie gesagt für das eigentliche Hervorheben zuständig. Der Trick besteht darin, so wenig Text wie nur möglich zu bearbeiten. Deshalb wird auch nur das Wort vor dem Cursor untersucht, das gerade eingegeben wird. Die gesamte Textzeile zu aktualisieren wäre zwar einfacher, dauert aber schon zu lange.
Der Code für die Texthervorhebungen befindet sich in der HilightAt-Methode. Als Parameter wird ein Index auf ein Zeichen übergeben. Der Index darf um 1 grösser sein als die Position des letzten Zeichens im hervorzuhebenden Wort. Er entspricht damit der Cursorposition, wenn das Wort gerade eingegeben wird. Den Code der Methode habe ich hier in mehrere Blöcke aufgeteilt, um ihre Funktion besser beschreiben zu können.
Zunächst einmal wird der Text aus der RichTextBox benötigt. RichTextBox ist eine Eigenschaft von RichTextBoxKeywordHilighter.
C#-Code: |
// Der Text.
|
Jetzt kann das Wort vor der Cursorposition gesucht werden. Zuerst wird der Wortanfang ermittelt.
C#-Code: |
// Wortanfang ermitteln.
|
Hier der im Code verwendete, reguläre Ausdruck wordStartRegex. Er sucht ausgehend vom Cursor rückwärts:
C#-Code: |
private static readonly Regex wordStartRegex = new Regex(
|
Ab Wortanfang wird wieder vorwärts nach dem Wortende gesucht.
C#-Code: |
// Wortende ermitteln.
|
Hier der zugehörige, reguläre Ausdruck wordEndRegex:
C#-Code: |
private static readonly Regex wordEndRegex = new Regex(
|
Aus Wortanfang und Wortende wird die Wortlänge ermittelt. Ist sie 0, gibt es nichts zu highlighten und es kann sofort abgebrochen werden:
C#-Code: |
// Wortlänge ermitteln. Ist die Länge 0, gleich zurück.
|
Wurde ein Wort gefunden, wird überprüft ob es sich um ein Schlüsselwort handelt. Dementsprechend wird eine Textfarbe ausgewählt. KeywordColor ist wieder eine Eigenschaft von RichTextBoxKeywordHilighter.
C#-Code: |
// Das Wort am Index.
|
Nun folgt das eigentliche Hervorheben. Zuvor muss aber noch die aktuelle Selektion der RichTextBox gesichert werden. Sie legt auch die Cursorposition fest, die im Anschluss wieder hergestellt werden muss. Das geschied in den Methoden BeginUpdate und EndUpdate.
C#-Code: |
BeginUpdate();
|
Wie man am Code sieht, gibt es einen Sonderfall, der extra behandelt werden muss. Normalerweise wird nur das Wort vor dem Cursor beachtet. Wird jedoch ein Wort durch einen Tastendruck in zwei Wörter aufgetrennt, kann sich auch die Farbe des Wortes hinter dem Cursor ändern. In dem Fall wird HilightAt einfach ein zweites Mal aufgerufen.
Der Code, wie er jetzt ist, funktioniert eigentlich schon zufriedenstellend. Es gibt keine Verzögerungen beim Tippen und gleichzeitigem Highlighting. Allerdings sind die in HilightAt programmatisch vorgenommenen Selektionen für den Benutzer sichtbar. Sie fallen durch kurzes Aufblitzen unangenehm auf. Dieses Problem löst die RichTextBoxUpdater-Klasse. Den Code hierfür habe ich in Pete's Weblog gefunden:
Pete's Weblog:
Extending RichTextBox, Part IRichTextBoxUpdater
RichTextBoxUpdater definiert zwei Methoden, BeginUpdate und EndUpdate. BeginUpdate deaktiviert die Aktualisierung der RichTextBox-Anzeige während vom Programm Textänderungen vorgenommen werden. EndUpdate reaktiviert die Aktualisierung wieder. Leider gibt es in der RichTextBox-Klasse keine Methoden, die das erledigen. Es muss also wiedermal auf P/Invoke und die Win-Api zurückgegriffen werden.
Die Einzelheiten können auf der angegebenen Seite nachgelesen werden, hier nur noch der Code für die Klasse:
C#-Code: |
class RichTextBoxUpdater {
|
Das war's auch schon. So sieht das Ergebnis aus:

Wenn ihr Lust habt, probiert die angehängte Demo-Anwendung aus. Die Zip-Datei enthält auch den kompletten Quellcode, den ihr nach Belieben zerpflücken und in eigene Anwendungen einbauen könnt. Bei Pete's Code bin ich mir nicht so sicher, aber ich denke, dass eine Quellenangabe ausreichen sollte.
In einem zweiten Teil werde ich die RichTextBoxKeywordHilighter-Klasse nochmal um das Highlighten für Textbereiche erweitern, damit sie auch beim Laden von Textdateien und bei Copy&Paste funktioniert.
Gruss
Pulpapex

.