Vorwort
So hallo an alle, ich hab mir mal überlegt, ich erstell mal ein tut für nen leistungfähigen, aber noc langsammen Syntax-Highlighter, wie wir ihn aus dem VS kennen ^^. Im I-net findet mal nämlich relativ wenig darüber..
Schritt 1
Zuerste erstellen wir ein einfaches WinForms Projekt, ich nenne es SyntaxHighlighterDemo.
Schritt 2
Jetzt erstellen wir eine neue Codedatei (FixedRichTextBox.cs) und erstetzen den kompletten Text, inklusive den using-Statements hierdurch:
Wie ihr seht, ist die Klasse von RichTextBox abgeleitet, ist dadurch ein Steuerelement und kann wie eine TextBox, ein Button o.ä. auf einer Winformsanwendung plaziert werden.
Aber, was haben wir hier gemacht? Weil die Klasse von RichTextBox abgeleitet ist, hat sie auch alle funktionen. Die RichTextBoxklasse hat aber einen Bug: Wenn man AutoWordSelection = false macht, müsste man theoretisch auch einzelne Buchstaben oder halbe Wörter markieren können, das funktioniert aber nicht. Diesen Fehler behebt man, indem man die Eigenschaft manuell auf true und anschließend auf false setzt. Die könnte man theoretisch auch in Form1_Load machen, so müsst ihr euch aber keine Sorgen darum machen das ihr es vergesst, sondern könnt einfach FixedRichTextBox statt RichTextBox verwenden.
Anyway, jetzt kompilern wir das ganze, entweder mit F5 oder F6, und öffnen Form 1.
Schritt 3
Als nächstes öffnen wir die ToolBox, und dadaa, unter SyntaxHighlighterDemo-Komponenten finden wir eine komponente mit dem Namen FixedRichTextBox.
[Blockierte Grafik: http://www.abload.de/img/fixedgnj3.png]
Diese platzieren wir wie normale Elemente auf der Form, wenn ihr wollt, platziert daneben eine normale RichTextBox um unseren oberen Fix zu veranschaulichen.
Schritt 4
Durch ein Doppelklick auf die FixedRichTextBox, erstellen wir das TextChanged-Event.
Dort fügen wir SyntaxHighlighter(); ein. Ich erstellle für den Highight eine neue Methode, damit ihr sie mehrmals verwenden könnt, und sie immer nur aufrufen müsst.
Diese Methode müssen wir auch erstellen, aber befor wir ihrgenwelchen Code eingeben, erstellen wir 1 Membervariable. Membervariablen sind Variablen, die in einer Klasse, und nich in einer Methode deklariert werden. Wir erstellen es also parktisch über dem Konstruktor von Form1.
Schritt5
Ein Dictionary ist das selbe wie eine List, der Vorteil ist aber, das wir mit dem aufruf von colors[key] einfach den Wert auslesen können, der zu dieser Key gehört.
Im Konstruktor müssen wir einfach Werte dafür festlegen.
Das erste Wort (Test) ist unser Keyword, wenn das Wor in der RichTextBox vorkommt, wird es blau markiert (Value).
Schritt 6
Als nächstes müssen wir 1 weiteren Fix machen, was ganau passier ist unwichtig, bzw. weiß ich es nicht, weil ich diesen Teil aus dem I-net hab
- private const int WM_SETREDRAW = 0xB;
- [System.Runtime.InteropServices.DllImport("User32")]
- private static extern bool SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
- private void FreezeDraw()
- {
- SendMessage(fixedRichTextBox1.Handle, WM_SETREDRAW, 0, 0);
- }
- private void UnfreezeDraw()
- {
- SendMessage(fixedRichTextBox1.Handle, WM_SETREDRAW, 1, 0);
- fixedRichTextBox1.Invalidate(true);
- }
fixedRichTextBox1 müsst ihr durch nameEurerRichTextBox ersetzen.
Schritt 7
Jetzt können wir endlich mit dem Code anfangen. Ab jetzt arbeiten wir nurnoch mit der Methode SyntaxHighlighter.
Zuerst fügen wir
ein. Dieser Code sorgt dafür, das wir nicht mitbekommen, wie jedes einzelne Wort markiert wir (dazu später mehr). unser kompletter Code kommt zwischen die beiden Freeze-Methoden.
Schritt 8
fügen wir direkt nach FreezeDraw ein. zuerst spalten wir den ganzen Text in einzelne Wörter. Space bzw. ein Absatz sind ein nues Wort.
startChar ist der anfang des Textes.
Als nächstes loopen wir durch jedes Wort und ermitteln die länge des Wortes + die länge von Space, die wir anschließend zu startChar hinzufügen:
Hinweis: weiterer Code kommt ab jetzt immer dahin, wo //... steht.
Jetzt müssen wir durch jedes Keyword, das markiert werden soll loopen. Weil das Keywor immer der erste Wert im colors-Dictionary ist, geht das sehr einfach mit:
Jetzt müssen wir schauen ob key == word ist, dann heben wir es nämlich farbig hervor. Sonst soll word einfach schwarz bleiben.
Hier ist der Code für das herausheben, diesen fügen wir in if- und else ein. Erklären werde ich ihn durch Kommentare:
if-Clause:
- int cursor = fixedRichTextBox1.SelectionStart; //Zuerst merken wir uns die Cursor-Position
- int wordLength = word.Length; //Die Länge des Wortes
- int wordStart = fixedRichTextBox1.Find( //wir ermitteln die Position des Anfangsbuchstaben
- word, //Das Wort das wir suchen
- startChar, //StartChar ist der Endwert des letzten Wortes
- fixedRichTextBox1.Text.Length, //Die Länge des Textes, den wir durchsuchen wollen, in unserem Fall den ganzen
- RichTextBoxFinds.NoHighlight); //Damit das gefundene Wort nicht markiert wird.
- fixedRichTextBox1.Select(wordStart, wordLength); //Hier wird das Wort markiert
- fixedRichTextBox1.SelectionColor = colors[key]; //Hier wird es eingefärbt, indem wir den Wert, der zur Key gehört benutzen.
- fixedRichTextBox1.Select(cursor, 0); //Es wird wieder nichts ausgewählt
- fixedRichTextBox1.SelectionColor = System.Drawing.Color.Black; //Damit weiterer Text wieder schwarz wird, färben wie das jetzt ausgewählte schwarz
- fixedRichTextBox1.SelectionStart = cursor; //den Cursor wieder an die ursprünglich position.
- break; //Wort ist markiert, wir müssen nicht mehr die anderen Farben durchlaufen
else-Clause
- //funktionier wie die if-Clause
- int cursor = fixedRichTextBox1.SelectionStart;
- int wordLength = word.Length;
- int wordStart = fixedRichTextBox1.Find(
- word,
- startChar,
- fixedRichTextBox1.Text.Length,
- RichTextBoxFinds.NoHighlight);
- if (wordStart != -1)
- {
- fixedRichTextBox1.Select(wordStart, wordLength);
- fixedRichTextBox1.SelectionColor = System.Drawing.Color.Black;
- fixedRichTextBox1.Select(cursor, 0);
- }
- fixedRichTextBox1.SelectionStart = cursor;
Wenn wir das ganze ausführen, wird, wenn wir Test schreiben, Test automatisch blau:
[Blockierte Grafik: http://www.abload.de/img/highlight1wy8s.png]
- private void SyntaxHighlighter()
- {
- FreezeDraw();
- string script = fixedRichTextBox1.Text;
- string[] words = script.Split(' ', '\n');
- int startChar = 0;
- foreach (string word in words)
- {
- int oldWordLength = word.Length + " ".Length;
- foreach (string key in colors.Keys)
- {
- if (word == key)
- {
- int cursor = fixedRichTextBox1.SelectionStart;
- int wordLength = word.Length;
- int wordStart = fixedRichTextBox1.Find(
- word,
- startChar,
- fixedRichTextBox1.Text.Length,
- RichTextBoxFinds.NoHighlight);
- fixedRichTextBox1.Select(wordStart, wordLength);
- fixedRichTextBox1.SelectionColor = colors[key];
- fixedRichTextBox1.Select(cursor, 0);
- fixedRichTextBox1.SelectionColor = System.Drawing.Color.Black;
- fixedRichTextBox1.SelectionStart = cursor;
- break;
- }
- else
- {
- int cursor = fixedRichTextBox1.SelectionStart;
- int wordLength = word.Length;
- int wordStart = fixedRichTextBox1.Find(
- word,
- startChar,
- fixedRichTextBox1.Text.Length,
- RichTextBoxFinds.NoHighlight);
- if (wordStart != -1)
- {
- fixedRichTextBox1.Select(wordStart, wordLength);
- fixedRichTextBox1.SelectionColor = System.Drawing.Color.Black;
- fixedRichTextBox1.Select(cursor, 0);
- }
- fixedRichTextBox1.SelectionStart = cursor;
- }
- }
- startChar += oldWordLength;
- }
- UnfreezeDraw();
- }
Schritt 9
Ist doch alles ganz schön, but, let's do some more stuff!
Wie wäre es zum Beispiel mit... grünen Kommentaren?
Zuerst fügen wir unter startChar = 0; eine boolvariable ein:
Bevor wir word == key checken, fügen wir diesen Code ein:
- if (word.StartsWith("//") || isComment == true) //Wenn das Wort mit //beginnt oder das Kommentar aktiv ist wird es grün.
- {
- int cursor = fixedRichTextBox1.SelectionStart;
- int wordLength = word.Length;
- int wordStart = fixedRichTextBox1.Find(
- word,
- startChar,
- fixedRichTextBox1.Text.Length,
- RichTextBoxFinds.NoHighlight);
- if (wordStart != -1)
- {
- fixedRichTextBox1.Select(wordStart, wordLength);
- fixedRichTextBox1.SelectionColor = System.Drawing.Color.FromArgb(0, 128, 0); //Eine dunkelgrün, unsere Kommentarfarbe
- }
- fixedRichTextBox1.Select(cursor, 0);
- isComment = true; //Kommentar aktiv
- if (word.EndsWith("//")) //Wenn das Wort mit // aufhört..
- {
- isComment = false; //..Ist das Kommentar abgeschlossen
- fixedRichTextBox1.SelectionColor = System.Drawing.Color.Black; //.. der weiterfolgende Text wird schwarz.
- }
- break; //Wir wollen ja nicht, das das Ward geHighlightet wird, auch wenn es ein Keyword ist
- }
Das wars auch schon:
[Blockierte Grafik: http://www.abload.de/img/highlight295qd.png]
Mit dem selben Prinzip könnt ihr auch etwas rot hervorheben, wenn es sich zwischen " und " befindet.
Ihr könnt auch eine Funktion einbauen, dass, wenn das vorangegangene Wort blau war, ihr das nächste Wort automatisch schwarz färbt, auch wenn es ein Keyword ist.
Das alle ist aber sehr einfach zu programmieren, versucht es einfach selbst
- private void SyntaxHighlighter()
- {
- FreezeDraw();
- string script = fixedRichTextBox1.Text;
- string[] words = script.Split(' ', '\n');
- int startChar = 0;
- bool isComment = false;
- foreach (string word in words)
- {
- int oldWordLength = word.Length + " ".Length;
- foreach (string key in colors.Keys)
- {
- if (word.StartsWith("//") || isComment == true)
- {
- int cursor = fixedRichTextBox1.SelectionStart;
- int wordLength = word.Length;
- int wordStart = fixedRichTextBox1.Find(
- word,
- startChar,
- fixedRichTextBox1.Text.Length,
- RichTextBoxFinds.NoHighlight);
- if (wordStart != -1)
- {
- fixedRichTextBox1.Select(wordStart, wordLength);
- fixedRichTextBox1.SelectionColor = System.Drawing.Color.FromArgb(0, 128, 0);
- }
- fixedRichTextBox1.Select(cursor, 0);
- isComment = true;
- if (word.EndsWith("//"))
- {
- isComment = false;
- fixedRichTextBox1.SelectionColor = System.Drawing.Color.Black;
- }
- break;
- }
- if (word == key)
- {
- int cursor = fixedRichTextBox1.SelectionStart;
- int wordLength = word.Length;
- int wordStart = fixedRichTextBox1.Find(
- word,
- startChar,
- fixedRichTextBox1.Text.Length,
- RichTextBoxFinds.NoHighlight);
- fixedRichTextBox1.Select(wordStart, wordLength);
- fixedRichTextBox1.SelectionColor = colors[key];
- fixedRichTextBox1.Select(cursor, 0);
- fixedRichTextBox1.SelectionColor = System.Drawing.Color.Black;
- fixedRichTextBox1.SelectionStart = cursor;
- break;
- }
- else
- {
- int cursor = fixedRichTextBox1.SelectionStart;
- int wordLength = word.Length;
- int wordStart = fixedRichTextBox1.Find(
- word,
- startChar,
- fixedRichTextBox1.Text.Length,
- RichTextBoxFinds.NoHighlight);
- if (wordStart != -1)
- {
- fixedRichTextBox1.Select(wordStart, wordLength);
- fixedRichTextBox1.SelectionColor = System.Drawing.Color.Black;
- fixedRichTextBox1.Select(cursor, 0);
- }
- fixedRichTextBox1.SelectionStart = cursor;
- }
- }
- startChar += oldWordLength;
- }
- UnfreezeDraw();
- }
Nachwort
Joa, das wars auch schon mit dem Tut, ist etwas länger geworden als ich dachte... Wenn es Fragen, Anregungen, Feedback, Bugreports oder so etwas gibt, einfach Posten
Rechtschreibfehler bitte ich zu entschuldigen, ich hoffe alles ist gut leserlich und verständlich
(C) Toast, Kopieren ist Ok, allerdings mit meinem Copyright.