C#開發高亮語法編輯器(一)——TextBox ,RichTextBox

一、RichTextBox基本設置
二、實現語法高亮
三、關鍵字提示
四、實現行號

就簡單快速得開發文本編輯器TextBox 最爲簡單,大家用得也多,缺點是無法實現複雜的操作。RichTextBox雖然是則功能比它強大很多。

單擊顯示全圖,Ctrl+滾輪縮放圖片

這裏要實現以下功能的編輯器:

1、實現語法高亮;
2、關鍵字提示;
3、行號。

顯然TextBox 無法完成我們的任務,雖然都派生自TextBoxBase,但就控制力而言RichTextBox比它優秀很多。這裏選用RichTextBox嘗試開發。

注:以下只討論簡單開發,不考慮複雜的關鍵字查找機制。


一、RichTextBox基本設置

這裏先建立一個工程,建立窗體Form1。
可以簡單添加RichTextBox控件,可以在Form1_Load中建立。代碼如下:
cs.gif複製  Save.jpg保存
this.WindowState = System.Windows.Forms.FormWindowState.Maximized;

RichTextBox rich = new RichTextBox();
rich.Multiline = true;
rich.Height = this.Height - 100;
rich.Width = this.Width - 100;
rich.Left = 40;
rich.Top = 40;
rich.WordWrap = true;
rich.Text = "12345678";
rich.ScrollBars = RichTextBoxScrollBars.ForcedVertical;
this.Controls.Add(rich);

這樣就建立了簡單的RichTextBox,寬度和高度都設置了。沒有做Form1窗體縮放的處理。


二、實現語法高亮

在RichTextBox裏實現語法高亮還是非常簡單的。可以使用
cs.gif複製  Save.jpg保存
rich.Select(0, 1);
rich.SelectionFont = new Font("宋體", 12, (FontStyle.Regular));
rich.SelectionColor = Color.Blue;

意思是,先選擇第一個字母,按上面的設置,選擇到了數字‘1’,然後設置這個字的字體大小,再設置字的顏色。

如果對關鍵字進行處理(這裏只處理光標向後流動的情況)
首先添加輸入事件
cs.gif複製  Save.jpg保存
rich.KeyDown += new KeyEventHandler(rich_KeyDown);   //這一行添加到Form1_Load中

void rich_KeyDown(object sender, KeyEventArgs e)
{
 //throw new Exception("The method or operation is not implemented.");
}

建立關鍵字
cs.gif複製  Save.jpg保存
public static List<string> AllClass()
{
    List<string> list = new List<string>();
    list.Add("function");
    list.Add("return");
    list.Add("class");
    list.Add("new");
    list.Add("extends");
    list.Add("var");
    return list;
}

當KeyDown事件發生時,向前查找
cs.gif複製  Save.jpg保存
//返回搜索字符
public static string GetLastWord(string str, int i)
{
    string x = str;
    Regex reg = new Regex(@"/s+[a-z]+/s*", RegexOptions.RightToLeft);
    x = reg.Match(x).Value;

    Regex reg2 = new Regex(@"/s");
    x = reg2.Replace(x, "");
    return s;
}

cs.gif複製  Save.jpg保存
void rich_KeyDown(object sender, KeyEventArgs e)
{
    RichTextBox rich = (RichTextBox) sender;
    //throw new Exception("The method or operation is not implemented.");
    string s = GetLastWord(rich.Text, rich.SelectionStart);

    if (AllClass().IndexOf(s) > -1)
    {
        MySelect(rich, rich.SelectionStart, s, Color.CadetBlue, true);
    }
}

cs.gif複製  Save.jpg保存
//設定顏色
public static void MySelect(System.Windows.Forms.RichTextBox tb, int i, string s, Color c, bool font)
{
    tb.Select(i - s.Length, s.Length);
    tb.SelectionColor = c;
    //是否改變字體
    if (font)
        tb.SelectionFont = new Font("宋體", 12, (FontStyle.Bold));
    else
        tb.SelectionFont = new Font("宋體", 12, (FontStyle.Regular));
    //以下是把光標放到原來位置,並把光標後輸入的文字重置
    tb.Select(i, 0);
    tb.SelectionFont = new Font("宋體", 12, (FontStyle.Regular));
    tb.SelectionColor = Color.Black;
}

這樣就完成了高亮工作。


三、關鍵字提示

實現關鍵字提示也是在KeyDown中實現,在提示字種搜索GetLastWord返回的文字,如果前半部分匹配。那麼就建立ListBox控件。
cs.gif複製  Save.jpg保存
void tb_KeyDown(object sender, KeyEventArgs e)
{
    RichTextBox tb = (RichTextBox) sender;
    if (/*條件搜索到匹配字符*/)
    {
        //搜索ListBox是否已經被創建
        Control[] c = tb.Controls.Find("mylb", false);
        if (c.Length > 0)
            ((ListBox) c[0]).Dispose();  //如果被創建則釋放

        ListBox lb = new ListBox();
        lb.Name = "mylb";
        lb.Items.Add("asdasdasd");
        lb.Items.Add("asdasdasd");
        lb.Items.Add("asdasdasd");
        lb.Items.Add("asdasdasd");
        lb.Items.Add("asdasdasd");
        lb.Items.Add("asdasdasd");
        lb.Items.Add("asdasdasd");
        lb.Show();
        lb.TabIndex = 100;
        lb.Location = tb.GetPositionFromCharIndex(tb.SelectionStart);
        lb.Left += 10;
        tb.Controls.Add(lb);
    }
}

當然,另外一面,如果創建ListBox,而又在RichTextBox 點擊了鼠標也去釋放。
cs.gif複製  Save.jpg保存
void rich_MouseClick(object sender, MouseEventArgs e)
{
    RichTextBox tb = (RichTextBox) sender;
    Control[] c = tb.Controls.Find("mylb", false);
    if (c.Length > 0)
        ((ListBox) c[0]).Dispose();
}

當然還得在Form1_Load裏註冊事件
cs.gif複製  Save.jpg保存
rich.MouseClick += new MouseEventHandler(rich_MouseClick);

然後設置ListBox 被選擇後用被選擇的關鍵字替換前文搜索到的字符。

下面我們來看看實現行號。


四、實現行號

這個是RichTextBox 唯一令我遺憾的地方,居然無法實現行號問題。爲什麼呢?我首先想到的是自己畫。用rich.CreateGraphics()來畫。但是,由於畫的時候發生在窗體被創建時,所以畫不成功,而被RichTextBox 本身的繪製給覆蓋了。

然後我選擇了在裏面添加Label控件
cs.gif複製  Save.jpg保存
Label l = new Label();
l.Name = "l";
l.Top = 0;
l.TextAlign = ContentAlignment.TopRight;
l.Width = 40;
l.Text = "1";
l.Font = new Font("宋體", 12, (FontStyle.Regular));
l.Height = this.Height;
l.BackColor = Color.Gray;
l.BorderStyle = BorderStyle.None;
rich.Controls.Add(l);

rich.SelectionIndent = 40;

rich.SelectionIndent = 40;是把光標對齊到左邊距40的位置,防止光標被Label覆蓋。

實現編號還不是太難。麻煩出在如何讓Lable能跟隨RichTextBox 的滾動條滾動。不說實現的 細節,我就假設,如果滾動條向上滾,那麼Lable的Top屬性增加,反之則減少。但是,RichTextBox 居然無法對ScollBar進行監測。

根本每辦法知道滾動條滾動了多少位置,甚至都沒辦法知道滾動條滾動的方向。

嘗試去除滾動條,然後之間添加新的滾動條
cs.gif複製  Save.jpg保存
VScrollBar vs = new VScrollBar();
//vs.Dock = DockStyle.Right;
vs.Name = "vs";
vs.Maximum = 0;
vs.Minimum = 0;
vs.MaximumSize = new Size(0, 0);
vs.Top = 0;
vs.Left = rich.Parent.Width - 100 - 22;
vs.Height = rich.Parent.Height - 100 - 1;
vs.Value = 0;
vs.Scroll += new ScrollEventHandler(vs_Scroll);

rich.Controls.Add(vs);

但是非常難於實現同步滾動,位置很難控制。這個就是目前遇到的RichTextBox 的最大侷限性了,非常遺憾,無法開發出這個功能。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章