全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:3598
推到 Plurk!
推到 Facebook!

RichEdit Syntax Highlighting 教學

 
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-08-28 10:53:49 IP:61.218.xxx.xxx 未訂閱

RichEdit Syntax Highlighting

Applies To: C Builder 1 or higher Category: Technical Articles Download: Source code 資料來源: http://free.prohosting.com/~cbdn/ [1]. Overview Many code editors, including C Builder, offer syntax-highlighting capabilities. I recently wanted to create a simple editor that displays keywords in a specific color. Although this may seem like a simple task, it isn't. Unless done correctly, syntax highlighting may be very slow and extremely flickery. [2]. Changing Color Before starting the actual project, you should of course know how to change the color of particular text in the RichEdit component. This is done by using the SelAttributes property. SelAttributes modifies the font characteristics of the currently selected text. If, for example, the text contained in your RichEdit component is "This is a text.", then you can use the following code to change the font color and style of the word "text":
  
RichEdit1->SelStart = 10; 
RichEdit1->SelLength = 4; 
RichEdit1->SelAttributes->Color = clBlue; 
RichEdit1->SelAttributes->Style = TFontStyles() << fsBold; 
Unfortunately, VCL methods and properties like this one are slower then the corresponding API calls. For this reason, I've decided to use only API functions and messages. Here's how the previous code should look like:
 
CHARRANGE Range; 
Range.cpMin = 10; 
Range.cpMax = 14; 
RichEdit1->Perform(EM_EXSETSEL, 0, (LPARAM)&Range); 
  
CHARFORMAT Format; 
memset(&Format, 0, sizeof(Format)); 
Format.cbSize = sizeof(Format); 
Format.dwMask = CFM_BOLD | CFM_COLOR; 
Format.dwEffects = CFE_BOLD; 
Format.crTextColor = clBlue; 
RichEdit1->Perform(EM_SETCHARFORMAT, SCF_SELECTION, 
    (LPARAM)&Format); 
[3]. Finding Keywords All keywords to be highlighted are stored in a simple array:
 
char *Keywords[ 8 ] = 
{ 
    "for", "int", "while", "do", "switch", "break", "case", "if" 
}; 
  
To check if a particular keyword is found in the text, you should use the EM_FINDTEXT message. For example: 
  
        FINDTEXT FindText; 
        FindText.lpstrText = Keywords[x]; 
        FindText.chrg.cpMin = Start; 
        FindText.chrg.cpMax = End; 
        FoundPos = RichEdit1->Perform(EM_FINDTEXT, 
                FT_WHOLEWORD, (LPARAM)&FindText); 
  
        while(FoundPos > -1) 
        { 
            ... 
I don't have place here to discuss each line of code. A complete description of messages and functions used here can be found in the C Builder help files. [4]. Line By Line A common error made when creating syntax highlighting editors is to parse the entire text. You should highlight words only in the current line. To do so, you need to know three things: the current line, the index of the first character and the index of the last character of this line. I've simplified this process by creating two functions:
  
int TForm1::GetFirstPos(int Line) 
{ 
    int Pos = RichEdit1->Perform(EM_LINEINDEX, Line, 0); 
    return Pos; 
} 
  
int TForm1::GetLastPos(int Line) 
{ 
    if(Line == RichEdit1->Lines->Count - 1) 
        return RichEdit1->Text.Length(); 
    else 
    { 
        int Pos = RichEdit1->Perform(EM_LINEINDEX, Line   1, 0); 
        return (Pos - 1); 
    } 
} 
Here's how you should use them:
    int CurrentLine = RichEdit1->Perform(EM_LINEFROMCHAR, 
        -1, 0); 
    int Start = GetFirstPos(CurrentLine); 
    int End = GetLastPos(CurrentLine); 
 
[5]. Improving Performance If, at this time, you try to build and execute this project, you'll see that the highlighting is slow and often flickers. To correct this problem, I've found three ways. The first one is to modify the event mask of your RichEdit component. The event mask specifies which notification messages RichEdit sends to its parent window. While you're syntax highlighting the text, no messages have to be sent to your form therefore, you can increase your application's performance using:
  
RichEdit1->Perform(EM_SETEVENTMASK, 0, ENM_NONE); 
 
and restoring the previous event mask once the process is finished. A second way to improve the look of your editor is by using the LockWindowUpdate API function. It simply disables the drawing of the RichEdit component. Finally, the last trick is to avoid repainting the current line if there are no new keywords. Each time you parse a certain line, you can store the number of keywords found in it. Then, the next time this line is modified, you could count the new number of keywords and compare it to the previous number. This operation may consume some memory but it greatly improves the look of your editor. [6]. Conclusion The complete source code is available for download here. This sample code editor is almost flicker-less and pretty fast, but there are many ways to improve it. You should, first of all, take care of the Paste and Undo commands since they're not correctly handled. You could then improve the text parsing or add new features to your editor. Good luck! C Builder Developer's Network Copyright © Yoto Yotov 聯盟----Visita網站http://www.vista.org.tw ---[ 發問前請先找找舊文章 ]--- 發表人 - axsoft 於 2002/08/28 11:00:58
lcsboy
版主


發表:87
回覆:622
積分:394
註冊:2002-06-18

發送簡訊給我
#2 引用回覆 回覆 發表時間:2002-08-29 02:16:13 IP:210.85.xxx.xxx 未訂閱
對於文章中提到"防止RichEdit閃動的三個建議" 小弟試了一下, 我用TRichEdit 寫的tool 1. 用EM_SETEVENTMASK, 0, 0的方式! 嗯! 還是怪怪的, 因為單行不閃動, 但會變成整頁閃動 <---worse /_\ 2. 使用API:LockWindowUpdate 哇! 超滿意! 真正達到不閃動, 但是看了一下我的tool的寫法 我還把WM_PAINT & WM_ERASEBKGND給直接作return, 完全不讓原來的有所動作 於是乎, 把code點掉 ---> 天啊, 好慘, 居然這邊不閃動, 其他會閃動 結論:1. 使用LockWindowUpdate 2. 攔截WM_PAINT & WM_ERASEBKGND, 然後裡面完全不讓它機會作, 直接return PS: 作者提到的第三個方式, 有點看不懂要表達什麼 @.@, 知道的人就回一下
artist1002
高階會員


發表:2
回覆:155
積分:151
註冊:2002-09-26

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-06-25 13:44:56 IP:211.76.xxx.xxx 未訂閱
引言: 對於文章中提到"防止RichEdit閃動的三個建議" 小弟試了一下, 我用TRichEdit 寫的tool 1. 用EM_SETEVENTMASK, 0, 0的方式! 嗯! 還是怪怪的, 因為單行不閃動, 但會變成整頁閃動 <---worse /_ 2. 使用API:LockWindowUpdate 哇! 超滿意! 真正達到不閃動, 但是看了一下我的tool的寫法 我還把WM_PAINT & WM_ERASEBKGND給直接作return, 完全不讓原來的有所動作 於是乎, 把code點掉 ---> 天啊, 好慘, 居然這邊不閃動, 其他會閃動 結論:1. 使用LockWindowUpdate 2. 攔截WM_PAINT & WM_ERASEBKGND, 然後裡面完全不讓它機會作, 直接return PS: 作者提到的第三個方式, 有點看不懂要表達什麼 @.@, 知道的人就回一下
第三個方式主要就是減少Highlight的動作. 每一次轉換一行的時候就計算這一行的keyword數量,儲存在記憶體 當某一行內容有變動的時候就重新計算. 之後的轉換就以記憶體中儲存的keyword數量來做 如果當行沒有keyword就不要作repaint 如此可以大幅減少repaint次數來達成不閃爍的目的
okeyla
一般會員


發表:51
回覆:20
積分:19
註冊:2003-06-12

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-08-04 18:11:26 IP:220.130.xxx.xxx 未訂閱
站長提出的方法, 若文字顏色不為黑色, 似乎會有錯誤耶... (第一行會對,可是換行後,文字顏色又跳回黑色) >_< What's going on?
系統時間:2024-11-23 21:49:08
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!