CRichEditCtrl добавление цветного текста?

У меня есть CRichEditCtrl в проекте MFC, который я использую в качестве журнала отчетов. В зависимости от конкретной ситуации мне нужно добавить разноцветный текст к элементу управления (т. Е. Синяя линия для стандартных уведомлений, красная линия для ошибок и т. Д.). Я подошел довольно близко к тому, чтобы заставить это работать, но оно все еще ведет себя странно:

void CMyDlg::InsertText(CString text, COLORREF color, bool bold, bool italic)
{
    CHARFORMAT cf = {0};
    CString txt;
    int txtLen = m_txtLog.GetTextLength();
    m_txtLog.GetTextRange(0, txtLen, txt);

    cf.cbSize = sizeof(cf);
    cf.dwMask = (bold ? CFM_BOLD : 0) | (italic ? CFM_ITALIC : 0) | CFM_COLOR;
    cf.dwEffects = (bold ? CFE_BOLD : 0) | (italic ? CFE_ITALIC : 0) |~CFE_AUTOCOLOR;
    cf.crTextColor = color;

    m_txtLog.SetWindowText(txt + (txt.GetLength() > 0 ? "\n" : "") + text);
    m_txtLog.SetSel(txtLen, m_txtLog.GetTextLength());
    m_txtLog.SetSelectionCharFormat(cf);
}

В лучшем случае конечный результат заключается в том, что вновь добавленная строка имеет соответствующий цвет, но весь предыдущий текст становится черным. Кроме того, для каждой добавленной строки текста начальный выбор увеличивается на 1. Например:

Call #1:
- [RED]This is the first line[/RED]

Call #2:
- [BLACK]This is the first line[/BLACK]
- [GREEN]This is the second line[/GREEN]

Call #3:
- [BLACK]This is the first line[/BLACK]
- [BLACK]This is the second line[/BLACK]
- [BLUE]This is the third line[/BLUE]

Call #4:
- [BLACK]This is the first line[/BLACK]
- [BLACK]This is the second line[/BLACK]
- [BLACK]This is the third line[/BLACK]
- [BLACK]T[/BLACK][YELLOW]his is the fourth line[/YELLOW]

Call #5:
- [BLACK]This is the first line[/BLACK]
- [BLACK]This is the second line[/BLACK]
- [BLACK]This is the third line[/BLACK]
- [BLACK]This is the fourth line[/BLACK]
- [BLACK]Th[/BLACK][ORANGE]is is the fifth line[/ORANGE]

etc...

Так как я могу исправить это так, чтобы весь предыдущий текст и форматирование оставались как есть, при добавлении новой строки цветного текста?

2 ответа

Решение

Ваш пример кода читает старый текст из диалога с вызовом GetTextRange(), Это не включает в себя никакого расширенного форматирования, поэтому, когда текст возвращается на место, он не форматируется. Вы можете полностью отказаться от этого, "вставив" в конец текстовой области, установив курсор в конец без какого-либо выделения и вызова ReplaceSel(),

Я думаю, что ваш метод должен выглядеть примерно так:

void CMFCApplication2Dlg::InsertText(CString text, COLORREF color, bool bold, bool italic)
{
    CHARFORMAT cf = {0};
    int txtLen = m_txtLog.GetTextLength();

    cf.cbSize = sizeof(cf);
    cf.dwMask = (bold ? CFM_BOLD : 0) | (italic ? CFM_ITALIC : 0) | CFM_COLOR;
    cf.dwEffects = (bold ? CFE_BOLD : 0) | (italic ? CFE_ITALIC : 0) |~CFE_AUTOCOLOR;
    cf.crTextColor = color;

    m_txtLog.SetSel(txtLen, -1); // Set the cursor to the end of the text area and deselect everything.
    m_txtLog.ReplaceSel(text); // Inserts when nothing is selected.

    // Apply formating to the just inserted text.
    m_txtLog.SetSel(txtLen, m_txtLog.GetTextLength());
    m_txtLog.SetSelectionCharFormat(cf);
}

Назначьте формат перед вставкой нового текста. Если вы примените формат после вставки, вы получите неправильно отформатированный текст.

CHARFORMAT cf = { 0 };
int txtLen =  GetTextLength();

cf.cbSize = sizeof(cf);
cf.dwMask = CFM_COLOR;
cf.dwEffects = ~CFE_AUTOCOLOR;//No auto color
cf.crTextColor = RGB(0, 0, 255);//color of the text

SetSel(txtLen, -1);//Deselect all
SetSelectionCharFormat(cf);//Assign the format to the cursor pos
ReplaceSel(newText);

Из этой работы я узнал, что нельзя просто установить флаги, как в приведенных выше примерах. Делая это:

 cf.dwMask = (bold ? CFM_BOLD : 0) | (italic ? CFM_ITALIC : 0) | CFM_COLOR;

Половина работает, но вы будете тратить много времени, если вы используете CRichEditCtrl (в качестве примера) и получаете текущее форматирование (хотя я думаю, что это происходило независимо от того, что для меня..) Проблема в том, что флаги выше установка того, что вы хотите переключить значение. Итак, это на самом деле более верно:

CHARFORMAT cf;
cf.cbSize = sizeof(CHARFORMAT);
GetSelectionCharFormat(cf);

cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_COLOR; //set these to specify the flags you are changing

if (bold)
{
    cf.dwEffects |= CFE_BOLD; //toggle on
}
else
{
    cf.dwEffects &= ~CFE_BOLD; //toggle off
}

if (italic)
{
    cf.dwEffects |= CFE_ITALIC; //toggle on
}
else
{
    cf.dwEffects &= ~CFE_ITALIC; //toggle off
}

cf.dwEffects &= ~CFE_AUTOCOLOR; //this only seemed to work if I set it this way

Если вы не сделаете это таким образом, форматирование останется - даже если вы очистили его. Это заставило меня почесать голову на некоторое время, и я много гуглил, чтобы это исправить.

Другие вопросы по тегам