簡體   English   中英

語法突出顯示Richedit控件無法正常工作

[英]syntax highlight richedit control not working poperly

我正在嘗試使用richedit實現語法高亮顯示編輯器,它與當前選定的行效果很好,但是我可能會遺漏一些東西。 CRichEdit是我自己的richedit控制器的包裝器實現,即使我確保使用代碼生成的所選范圍是我通過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);
}

EM_EXSETSEL EM_GETSELTEXT ,您可以考慮使用EM_FINDWORDBREAK來定位單詞,並使用EM_EXSETSEL / EM_GETSELTEXT來檢索每個單詞的字符,而不是使用getLine()strtok()來解析文本。 這樣,您將使用更少的內存,讓RichEdit為您執行更多搜索。 如果要自定義搜索的單詞定界符,可以使用EM_SETWORDBREAKPROC/EX

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM