У меня есть 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...
Так как я могу исправить это так, чтобы весь предыдущий текст и форматирование оставались как есть, при добавлении новой строки цветного текста?
Ваш пример кода читает старый текст из диалога с вызовом 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);
}
Из этого я понял, что нельзя просто установить флаги, как в приведенных выше примерах. Делая это:
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
Если вы не сделаете это таким образом, форматирование останется — даже если вы его очистили. Это заставило меня почесать голову на некоторое время, и я много гуглил, чтобы это исправить.