2014-07-06 149 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

你是什么意思?“它超出了可见的线条而忽略了多行文字”? –