我正在尝试使用richedit实现语法高亮显示编辑器,它与当前选定的行效果很好,但是我可能会遗漏一些东西。 CRichEdit是我自己的richedit Controller 的包装器实现,即使我确保使用代码生成的所选范围是我通过EM_EXGETSEL消息获得的范围,问题似乎也无法正确选择文本。
随着行数的减少,选择似乎增加了1,因此我决定将ed_source.sendMessage(EM_LINEFROMCHAR,pos,0)设置为部分解决该问题的范围,除了一些行,其中一些行看起来是着色的,或者是在行之前和之后真正合适的,所以这就是为什么我的事情我可能不了解。
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);
}
最佳答案
看一下这篇文章的一些想法:
更快的丰富编辑语法突出显示
http://bcbjournal.org/articles/vol3/9910/Faster_rich_edit_syntax_highlighting.htm
它是为C++ Builder中的TRichEdit
控件编写的,但其中的大多数技巧都使用直接的Win32 API调用,并且使用VCL惯用语的少数地方可以轻松地适应Win32等效项。
更新:尝试从循环中删除EM_LINEFROMCHAR
。 offset + 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
。关于c++ - 语法高亮显示丰富的编辑控件无法正常工作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24599547/