Подсветка синтаксиса RichEdit

Мне нужна ваша помощь! Итак, я создаю RichEdit с подсветкой синтаксиса, я делаю так:

   SendMessage(hWin, WM_SETREDRAW, false, 0);
            CHARFORMAT2 format, old;
            format.cbSize = sizeof(format);
            old.cbSize = sizeof(format);
            MainRich.GetFormat(SCF_DEFAULT, &format);
            MainRich.GetFormat(SCF_DEFAULT, &old);
            format.dwMask = CFM_BOLD;       
            format.dwEffects = CFE_BOLD;
            CHARRANGE* c = MainRich.GetSelectionRange();
            int length = MainRich.GetLength();
            string str = string(MainRich.GetText());
            #define hl "true" //Example of syntax for highlight
            int last = 0;
            while (str.find(hl, last)!=string::npos)
            {
                MainRich.Select(str.find(hl, last), str.find(hl, last)+strlen(hl));
                MainRich.SetFormat(SCF_SELECTION, &format);
                last = str.find(hl, last)+strlen(hl);
            }
            MainRich.Select(c->cpMin, c->cpMax);
            MainRich.SetFormat(SCF_SELECTION, &old);
            SendMessage(hWin, WM_SETREDRAW, true, 0);
            UpdateWindow(hWin);
            }

Но я вижу, что в больших файлах с большим количеством выделений он тормозит. У вас есть лучший способ сделать это? Я проверил Iczelion's Assembly, но этот код - беспорядок, он, кажется, рисует выделение перед текстом, но таким образом выделение не работает, верно? Если это так, можете ли вы дать мне несколько советов как это сделать? Спасибо!


person user3124543    schedule 01.03.2014    source источник


Ответы (3)


Самый быстрый способ, который я нашел, — создать необработанный документ RTF, а затем передать его в элемент управления через EM_STREAMIN сообщение.

EDITSTREAM stream;
stream.dwCookie = (DWORD_PTR)&streamData; // pointer your rtf data
stream.dwError = 0;
stream.pfnCallback = (EDITSTREAMCALLBACK)RtfStreamCallback; // callback which will push down the next chunk of rtf data when needed

LRESULT bytesAccepted = 0;
bytesAccepted = SendMessage(hWindow, EM_STREAMIN, SF_RTF, (LPARAM)&stream);

Еще одна вещь, о которой следует помнить, это то, что используемый вами элемент управления RTF серьезно влияет на производительность. Когда я сделал это, я обнаружил, что элемент управления по умолчанию (предоставленный Windows XP) был ужасно медленным, но RICHED20.DLL, предоставленный Microsoft Office, был на несколько порядков быстрее. Вы должны попробовать версии, к которым у вас есть доступ, и провести некоторое сравнение производительности.

Ссылка на спецификацию RTF 1.6

person josh poley    schedule 01.03.2014

Ваше использование MainRich.GetText() и избыточные вызовы std::string::find() являются узкими местами. Не восстанавливайте текст вообще. Вместо этого используйте CRichEditCtrl::FindText().

Не восстанавливайте исходный формат исходного выбора в конце. Что делать, если выделенное ключевое слово было выбрано до того, как вы применили выделение? Вы бы отменили выделение для него.

Еще одна оптимизация, которую вы можете сделать, чтобы ускорить RichEdit, — использовать CRichEditCtrl::SetEventMask() для отключать события (например, EN_SELCHANGE) при внесении изменений в текст, а затем восстанавливать их по завершении.

Попробуй это:

SendMessage(hWin, WM_SETREDRAW, false, 0);
CHARFORMAT2 format, old;
format.cbSize = sizeof(format);
MainRich.GetFormat(SCF_DEFAULT, &format);
old = format;
format.dwMask |= CFM_BOLD;       
format.dwEffects |= CFE_BOLD;
CHARRANGE* c = MainRich.GetSelectionRange();
DWORD mask = MainRich.GetEventMask();
MainRich.SetEventMask(0);
FINDTEXTEX ft;
ft.chrg.cpMin = 0;
ft.chrg.cpMax = MainRich.GetLength();
ft.lpstrText = "true";
while (MainRich.FindText(FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD, &ft) != -1)
{
    MainRich.Select(ft.chrgText.cpMin, ft.chrgText.cpMax);
    MainRich.SetFormat(SCF_SELECTION, &format);
    ft.chrg.cpMin = ft.chrgText.cpMax;
}
MainRich.Select(ft.chrg.cpMax, ft.chrg.cpMax);
MainRich.SetFormat(SCF_SELECTION, &old);
MainRich.Select(c->cpMin, c->cpMax);
MainRich.SetEventMask(mask);
SendMessage(hWin, WM_SETREDRAW, true, 0);
UpdateWindow(hWin);
person Remy Lebeau    schedule 01.03.2014

Окончательный подход к производительности заключается в том, чтобы API подключался к TextOut.

Чтобы указать 100% правильно.

  • riched32.dll (richedit v1.0) импортируется из riched20.dll.

  • riched20.dll (richedit v2.0) использует: ExtTextOutA и ExtTextOutW

  • msftedit.dll (richedit v4.1) использует: ExtTextOutA, ExtTextOutW и TextOutW.

person JonPall    schedule 03.03.2014
comment
Я подключился, и ничего не произошло ... RichEdit не запускает его - person user3124543; 04.03.2014