2014-07-06 148 views
1

我正在嘗試使用richedit實現語法高亮顯示編輯器,它與當前選定的行很好地工作,但我可能會丟失一些東西。 CRichEdit是我自己的richedit控制器的包裝器實現,問題似乎是即使我確保使用代碼生成的選定範圍是我通過EM_EXGETSEL消息得到的,但文本沒有被正確選擇。 選擇似乎增加1,因爲線條下降,所以我決定ed_source.sendMessage(EM_LINEFROMCHAR,pos,0)到部分解決問題的範圍,除了一些幾何線,其中着色似乎有一次或定位之前和真正的適當的,所以這就是爲什麼我的事情我可能不會理解的東西。語法突出顯示richedit控件不能正常工作

void parse(WIN::CRichEdit &ed_source, bool curseline) 
{ 
    int pos, offset = 0; 
    char delimiter[]={" \n\r(){};"}, *tok, *start; 
    CStringA s; 
    CString text; 
    CWnd api; 

    if(curseline){  
     ed_source.getLine(ed_source.getRow() - 1, text); 
     offset = ed_source.sendMessage(EM_LINEINDEX, -1, 0); 
    }else{ 
     text = ed_source.getCaption(); 
    } 

    s = text; 
    start = s.c_str(); 
    if(!start) return; 

    tok = strtok(s.c_str(), delimiter); 

    CHARRANGE cr = ed_source.getSelecteRange(); 
    ed_source.sendMessage(EM_HIDESELECTION, 1, 0) ; 
    CHARRANGE range; 
    while(tok) 
    { 
     int len = strlen(tok); 

     pos = (tok - start); 
     int x = ed_source.sendMessage(EM_LINEFROMCHAR, pos, 0); 
     range.cpMin = offset + pos - x; 
     range.cpMax = range.cpMin + len; 

     ed_source.selectRange(range); 
     if(isReserved(tok)){ 

      ed_source.setTextStyle(true, false); 
      ed_source.setTextColor(keyboardColor); 
     }else 
      if(isType(tok)){ 
       ed_source.setTextStyle(false, false); 
       ed_source.setTextColor(typeColor); 
      }else { 
       ed_source.setTextStyle(false, true); 
       ed_source.setTextColor(textColor); 
      } 
     tok = strtok(0, delimiter); 
    } 

    ed_source.sendMessage(EM_HIDESELECTION, 0, 0) ; 
    ed_source.selectRange(cr); 
} 

只是更具體的時刻,我呼籲上述功能是在加載文本後立即。我認爲你可能想看看上面的一些功能的實現,所以他們在這裏。

CHARRANGE CRichEdit::getSelecteRange() 
{ 
    CHARRANGE crg = {0} ; 
    sendMessage(EM_EXGETSEL, 0, (LPARAM)&crg); 
    return crg; 
} 

void CRichEdit::selectRange(const CHARRANGE &cr) 
{ 
    sendMessage(EM_EXSETSEL, 0, (LPARAM) &cr); 
} 


void CRichEdit::setTextColor(COLORREF col) 
{ 
    CHARFORMAT format; 
    memset(&format, 0, sizeof(CHARFORMAT)); 
    format.cbSize  = sizeof(CHARFORMAT); 
    format.dwMask  = CFM_COLOR; 
    format.crTextColor = col; 

    sendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &format); 
} 
+0

在richedit控件頂部的編輯器中高亮顯示語法將無法工作。您將永遠回頭瀏覽已經格式化的文本,然後重新進行處理。 –

回答

1

看一看這篇文章的一些想法:

更快豐富的編輯語法高亮 http://bcbjournal.org/articles/vol3/9910/Faster_rich_edit_syntax_highlighting.htm

它是爲在C++ Builder中的TRichEdit控制寫的,但多數人的其中的提示使用直接的Win32 API調用,而使用VCL慣用語的少數地方可以很容易地適用於Win32版本。

更新:嘗試從循環中刪除EM_LINEFROMCHARoffset + pos已經是RichEdit中的絕對字符位置,不需要在每次循環迭代時調整它。如果你真的想要考慮行索引,那麼你應該循環遍歷行中的每行一行,分別解析每行,而不是將整個內容解析爲單個字符串。嘗試一些更喜歡這個:

void parse(WIN::CRichEdit &ed_source, bool curseline) 
{ 
    int startLine, endLine, offset; 
    const char* delimiters = " \n\r(){};"; 
    char *tok, *start; 
    CStringA s; 
    CWnd api; 

    if (curseline) 
    { 
     startLine = ed_source.getRow() - 1; 
     endLine = startLine + 1; 
    } 
    else 
    { 
     startLine = 0; 
     endLine = ed_source.sendMessage(EM_GETLINECOUNT, 0, 0); 
    } 

    CHARRANGE cr = ed_source.getSelecteRange(); 

    int eventMask = ed_source.SendMessage(EM_SETEVENTMASK, 0, 0); 
    ed_source.SendMessage(WM_SETREDRAW, FALSE, 0); 

    for (int line = startLine; line < endLine; ++line) 
    { 
     CString text; 
     ed_source.getLine(line, text); 

     s = text; 
     start = s.c_str(); 
     if (!start) continue; 

     offset = ed_source.sendMessage(EM_LINEINDEX, line, 0); 

     tok = strtok(start, delimiters); 
     while (tok) 
     { 
      CHARRANGE range; 
      range.cpMin = offset + (int)(tok - start); 
      range.cpMax = range.cpMin + strlen(tok); 

      ed_source.selectRange(range); 
      if (isReserved(tok)) 
      { 
       ed_source.setTextStyle(true, false); 
       ed_source.setTextColor(keyboardColor); 
      } 
      else if (isType(tok)) 
      { 
       ed_source.setTextStyle(false, false); 
       ed_source.setTextColor(typeColor); 
      } 
      else 
      { 
       ed_source.setTextStyle(false, true); 
       ed_source.setTextColor(textColor); 
      } 

      tok = strtok(0, delimiters); 
     } 
    } 

    ed_source.SendMessage(WM_SETREDRAW, TRUE, 0); 
    ed_source.Invalidate(); // whatever your wrapper does to call ::InvalidateRect() 

    ed_source.SendMessage(EM_SETEVENTMASK, 0, eventMask); 

    ed_source.selectRange(cr); 
} 

雖這麼說,而是採用getLine()strtok()解析的文字,你可以考慮使用EM_FINDWORDBREAK查找單詞和EM_EXSETSEL/EM_GETSELTEXT中檢索每個字的字符。這樣,你就可以使用更少的內存,並讓RichEdit更多地搜索你。如果要自定義搜索的單詞分隔符,可以使用EM_SETWORDBREAKPROC/EX

+0

我看了一下,但是我沒有看到我不理解的部分。無論如何,我的大部分代碼都在工作。例如,當我只修改一行(當我使用curseline = true調用parse時),顏色正確應用。但是當我把它變成虛假的意思時,我想爲每一行着色就是選擇看起來有點過分。 – Jman

+0

我的第一次嘗試沒有EM_LINEFROMCHAR,因爲它應該像您提到的那樣是絕對位置,但是注意到隨着行號增加,它正在增加一個增加的char索引。正如你所說的逐行閱讀,除了在可見行之外留下更多的文字。 – Jman

+0

你是什麼意思?「它超出了可見的線條而忽略了多行文字」? –