Lekce 17 - Tvoříme vlastní Syntax Highlighter pomocí RichTextBox v C#
V předchozích 4 lekcích jsme pracovali se základními ovládacími prvky, které nabízí sám .NET Framework. Toto počínání jsme dovršili lekcí Ovládací prvky Windows Forms počtvrté.
V dnešním C# .NET Windows Forms tutoriálu naprogramujeme vlastní Syntax
Highlighter, tedy zvýrazňovač syntaxe v C# .NET, jako má např. Visual
Studio. Procvičíme si tím použití ovládacího prvku
RichTextBox
:

Návrh
Nejprve je třeba si rozvrhnout, jak vlastně bude náš program fungovat. Nejjednodušší, co určitě většinu z vás napadne, je mít nějakou kolekci s klíčovými slovy a jejich barvou, tu projet cyklem a podle toho text obarvovat. A přesně tak to i uděláme. Samozřejmě nesmíme očekávat extra výkon a chtít zvýrazňovač použít pro dlouhý kód. Hodí se spíše pro jednorázové zvýraznění. Ale my si vyzkoušíme i realtime. Efektivní zvýraznění bychom museli udělat pomocí tokenizace, což je nad rámec tohoto kurzu.
Návrh formuláře
Vytvoříme si novou Windows Forms aplikaci s názvem
EasySyntaxHighlighter
. Začneme tradičně návrhem formuláře.
Přidáme do něj ovládací prvky:
RichTextBox
na kód ke zvýraznění aButton
na zapnutí zvýraznění, realtime zvýraznění si totiž pro zjednodušení přidáme až později.
RichTextBox
bude moci psát odsazení tabulátorem, proto mu
povolíme AcceptsTab
. Tlačítku vytvoříme událost
OnClick
.
Slovníky
Nyní si vytvoříme třídu SyntaxHighlighter
.
Vytvoření slovníku
Přidáme do ní statickou kolekci keywords
typu
Dictionary
s typem klíče string
a hodnotou
Color
:
private static Dictionary<string, Color> keywords;
Dále přidáme veřejnou statickou metodu
void InitializeKeywords()
, ve které kolekci inicializujeme a
vložíme do ní naše klíčová slova. Můžeme přidat také jednoduché
ošetření if (keywords != null) return;
, aby metoda zbytečně
neproběhla vícekrát.
Statická je kolekce a metoda proto, že tato klíčová slova budou vždy stejná a je zbytečné ukládat je pro každou instanci highlighteru.
Naplnění slovníku
Najdeme si klíčová slova, která budeme zvýrazňovat. Budeme zvýrazňovat samozřejmě klíčová slova C#.
Klíčová slova z daných odkazů jednoduše zkopírujeme a v textovém editoru ořežeme tak, aby z nich vznikl dlouhý řádek jednotlivých slov oddělených čárkou, jako:
abstract,event,new,struct,as,explicit,null,switch,base,extern,this,false,operator,throw,break...
Teď je třeba smazat duplicitní slova. To můžeme udělat buď ručně
nebo si na to napsat malý C# program, který slova rozdělí podle čárky,
cyklem přidá do kolekce List
a pak zavolá
Distinct()
.
Klíčová slova je pak dobré roztřídit. Budeme rozlišovat jinou barvou datové typy a jinou ostatní klíčová slova. Klíčová slova budou třeba zelená, kdežto datové typy modré.
Ve výsledku dospějeme k následujícím řetězcům, které slova
definují. Pokud se vám nechce sestavovat si tyto definice ručně, můžete si
jen zkopírovat tyto proměnné. Vložíme je dále do metody
InitializeKeywords()
:
string CSharpKeywords = "abstract,event,new,struct,as,explicit,null,switch,base,extern,this,false,operator,throw,break,finally,out,true,fixed,override,try,case,params,typeof,catch,for,private,foreach,protected,checked,goto,public,unchecked,if,readonly,unsafe,implicit,ref,continue,in,return,using,virtual,default,interface,sealed,volatile,delegate,internal,do,is,sizeof,while,double,lock,stackalloc,else,static,namespace"; string DataTypes = "bool,object,byte,float,class,uint,char,ulong,ushort,const,decimal,int,sbyte,short,void,long,enum,string";
No a teď už jen jednoduše projedeme cyklem jednotlivá slova a přidáme je do kolekce s příslušnou barvou:
foreach (string word in CSharpKeywords.Split(',')) keywords.Add(word, Color.Green); foreach (string type in DataTypes.Split(',')) keywords.Add(type, Color.Blue);
Tuto metodu zavoláme v konstruktoru formuláře, který v něm již máme:
public Form1()
{
InitializeComponent();
SyntaxHighlighter.InitializeKeywords();
}
Zvýraznění
Nyní se přesuneme zpět do třídy SyntaxHighlighter
.
Přidáme sem veřejnou statickou metodu
HighlightText()
, která vrací string
a jejím
parametrem je string text
.
Metoda je opět statická, protože
SyntaxHighlighter
nenese žádná instanční data, je to jen
takový pomocník. Jestli chcete, můžete si celou třídu označit jako
static
.
V metodě si vytvoříme další pomocnou instanci RichTextBox
,
ve které si zvýrazněný dokument připravíme:
RichTextBox rtb = new RichTextBox(); rtb.Text = text; rtb.Font = new Font(FontFamily.GenericMonospace, 8.75f, FontStyle.Regular);
Obarvení klíčových slov
Dále projedeme všechna klíčová slova, vyhledáme je v textu a obarvíme příslušnou barvou:
int index; foreach (var entry in keywords) { index = 0; while ((index = rtb.Find(entry.Key, index, RichTextBoxFinds.WholeWord)) != -1) { rtb.Select(index, entry.Key.Length); rtb.SelectionFont = new Font(rtb.Font.FontFamily, rtb.Font.Size, FontStyle.Bold); rtb.SelectionColor = entry.Value; index += 1; } }
Proměnná index
určuje současnou pozici v textu. Při
hledání dalšího slova se postupuje od pozice toho předchozího. Přičítá
se k němu 1
, protože je v něm obsažena pozice, kde začíná
dané slovo a program by se zacyklil. Takto slovo usekneme a bude se hledat
dál.
Metoda Find()
vyhledá dané slovo, začíná hledat od dané
pozice a hledá pouze samostatná slova, tzn. např. "in"
najde,
ale "indeed"
už ne. Vrátí pozici, kde dané slovo začíná.
Pokud se v textu nevyskytuje, vrátí -1
.
Metoda Select()
vybere text, který začíná na dané pozici a
označí zadaný počet znaků. Dělá to samé, jako když klepneme a táhneme
myší přes text.
Nyní, když je text vybrán, zvolí se barva a písmo výběru pomocí
SelectionFont
a SelectionColor
.
Můžeme si dále zvýraznit i komentáře:
index = 0; while ((index = rtb.Text.IndexOf("//", index)) != -1) { rtb.Select(index, rtb.Text.IndexOf("\n", index) - index); rtb.SelectionFont = new Font(rtb.Font.FontFamily, rtb.Font.Size, FontStyle.Regular); rtb.SelectionColor = Color.Gray; index += 2; // zde se přičítá dvojka kvůli popiskům tzv. summary, kde jsou /// závorky, já je beru jako komentář. }
Nebo i string
"můj text"
či více řádkové
komentáře /* můj komentář */
, které lze jednoduše přidat
stejným způsobem jako jednořádkový komentář (viz projekt ke stažení pod
lekcí).
Testování
Nyní si zvýrazňovač vyzkoušíme. Pouze do události tlačítka přidáme:
richTextBox1.Rtf = SyntaxHighlighter.HighlightText(richTextBox1.Text);
A spustíme
Real-time zvýrazňování
Nyní si zkusíme real time zvýrazňování. Tzn., že budeme psát a bude
se nám text ihned zvýrazňovat. Tlačítko smažeme i s událostí.
RichTextBox
nastavíme dock, aby se nám pěkně roztáhl. A
přidáme mu událost KeyDown
, kde zvýraznění zavoláme.
Pokud jste někteří zkoušeli s předstihem, narazili jste pravděpodobně
na problém, že se vlastně nedá psát. Při zvýraznění se nám totiž
kurzor začne vracet na začátek. Tento problém ošetříme jednoduše
uložením současné pozice kurzoru SelectionStart
, zvýrazněním
textu a následným nastavením pozice kurzoru zpět. Kód obslužné metody pro
událost KeyDown
je tedy následující:
int lastSelectionStart = richTextBox1.SelectionStart;
richTextBox1.Rtf = SyntaxHighlighter.HighlightText(richTextBox1.Text);
richTextBox1.SelectionStart = lastSelectionStart;
Bystří z vás narazí na další problém, že pokud chceme něco označit a smazat, nejde to. To se dá snadno ošetřit kontrolou, zda je něco vybraného, tzn. délka výběru. Na začátek té samé obslužné metody přidáme:
if (richTextBox1.SelectionLength > 0) return;
A náš vlastní highlighter je na světě! V přiloženém archivu si můžete stáhnout verzi, která zvýrazňuje i textové řetězce a také jazyk PHP:

V příští lekci, Vlastní ovládací prvky v C# .NET, si ukážeme jak si vytvořit svůj vlastní ovládací prvek.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 433x (49.16 kB)
Aplikace je včetně zdrojových kódů v jazyce C#