Using RichEditCtrl to Display Formatted Logs
A simple demo to show you how to use the standard RichEditCtrl to print formatted text to a message/log window.

Introduction
This article shows how to use a CRichEditCtrl
control to print formatted messages to a message log window and how to implement auto-scrolling such that the control scrolls down as far as required to show the last line of text at the bottom of the control. The demo project includes a very simple dialog based application showing two alternate ways to implement this (a "naive" solution and a robust solution which supports dynamic resizing of the control).
In contrast to other solutions shown in the archives, this solution does not require you to use a derived version of CRichEditCtrl
. Simply see how it works and copy/modify the code to suit your application's requirements. The focus of this article is just to show beginners how easy it is to implement a formatted message log.
Targeted Audience
This article is for CRichEditCtrl
beginners only.
Step 1: Insert a CRichEditCtrl into your Dialog
- Using the GUI builder of Visual Studio, simply insert a
CRichEditCtrl
into your dialog template (named "Rich Edit 2.0 Control" in the Toolbox of Visual Studio). - Add a member variable for the Rich Edit Control using the Class Wizard. Select "Control" as variable type. I used the name
m_ctrlLog
. - Open the source file of your application and go to the
InitInstance
method. Insert the lineAfxInitRichEdit2();
right after theAfxEnableControlContainer();
line. - In the GUI builder, select the Rich Edit Control and change its properties to enable multiline support, vertical scrolling and write protection (read-only).
You are now ready to use the cRich
Edit Control as your message log. In the demo application, I have added a simple function to add colored messages to the control, as an example of how to add formatted text. You can extend your own code to support other formatting, such as bold, italic, strikethrough, and so on.
Step 2: Add a Method to Append Formatted Messages
I have written a two simple methods to add formatted text to the log. The following one is the "naive" version, which scrolls down by the number of lines you added, but which does not care about the current scrolling position:
int CRichEditLog_DemoDlg::AppendToLog(CString str, COLORREF color)
{
int nOldLines = 0, nNewLines = 0, nScroll = 0;
long nInsertionPoint = 0;
CHARRANGE cr;
CHARFORMAT cf;
// Save number of lines before insertion of new text
nOldLines = m_ctrlLog.GetLineCount();
// Initialize character format structure
cf.cbSize = sizeof(CHARFORMAT);
cf.dwMask = CFM_COLOR;
cf.dwEffects = 0; // To disable CFE_AUTOCOLOR
cf.crTextColor = color;
// Set insertion point to end of text
nInsertionPoint = m_ctrlLog.GetWindowTextLength();
/*if (nInsertionPoint > 800)
{
// Delete first half of text to avoid running into the 64k limit
m_ctrlLog.SetSel(0, nInsertionPoint / 2);
m_ctrlLog.ReplaceSel("");
UpdateData(FALSE);
}*/
nInsertionPoint = -1;
m_ctrlLog.SetSel(nInsertionPoint, -1);
// Set the character format
m_ctrlLog.SetSelectionCharFormat(cf);
// Replace selection. Because we have nothing selected, this will simply insert
// the string at the current caret position.
m_ctrlLog.ReplaceSel(str);
// Get new line count
nNewLines = m_ctrlLog.GetLineCount();
// Scroll by the number of lines just inserted
nScroll = nNewLines - nOldLines;
m_ctrlLog.LineScroll(nScroll);
return 0;
}
The "naive" version has some flaws. As it does not care about the current scrolling position, it does not scroll to the end if the user has scrolled somewhere else in the meantime.
A robust, much improved version is shown next. It uses a helper function GetNumVisibleLines()
to first determine the number of (fully) visible lines in the control and then scroll down to the maximum extend (then showing the last line of text at the top of the control) and then back by the number of visible lines (then showing the last text line at the bottom of the control).
int CRichEditLog_DemoDlg::AppendToLogAndScroll(CString str, COLORREF color)
{
long nVisible = 0;
long nInsertionPoint = 0;
CHARFORMAT cf;
// Initialize character format structure
cf.cbSize = sizeof(CHARFORMAT);
cf.dwMask = CFM_COLOR;
cf.dwEffects = 0; // To disable CFE_AUTOCOLOR
cf.crTextColor = color;
// Set insertion point to end of text
nInsertionPoint = m_ctrlLog.GetWindowTextLength();
m_ctrlLog.SetSel(nInsertionPoint, -1);
// Set the character format
m_ctrlLog.SetSelectionCharFormat(cf);
// Replace selection. Because we have nothing
// selected, this will simply insert
// the string at the current caret position.
m_ctrlLog.ReplaceSel(str);
// Get number of currently visible lines or maximum number of visible lines
// (We must call GetNumVisibleLines() before the first call to LineScroll()!)
nVisible = GetNumVisibleLines(&m_ctrlLog);
// Now this is the fix of CRichEditCtrl's abnormal behaviour when used
// in an application not based on dialogs. Checking the focus prevents
// us from scrolling when the CRichEditCtrl does so automatically,
// even though ES_AUTOxSCROLL style is NOT set.
if (&m_ctrlLog != m_ctrlLog.GetFocus())
{
m_ctrlLog.LineScroll(INT_MAX);
m_ctrlLog.LineScroll(1 - nVisible);
}
return 0;
}
int CRichEditLog_DemoDlg::GetNumVisibleLines(CRichEditCtrl* pCtrl)
{
CRect rect;
long nFirstChar, nLastChar;
long nFirstLine, nLastLine;
// Get client rect of rich edit control
pCtrl->GetClientRect(rect);
// Get character index close to upper left corner
nFirstChar = pCtrl->CharFromPos(CPoint(0, 0));
// Get character index close to lower right corner
nLastChar = pCtrl->CharFromPos(CPoint(rect.right, rect.bottom));
if (nLastChar < 0)
{
nLastChar = pCtrl->GetTextLength();
}
// Convert to lines
nFirstLine = pCtrl->LineFromChar(nFirstChar);
nLastLine = pCtrl->LineFromChar(nLastChar);
return (nLastLine - nFirstLine);
}
The rest of the demo application consists of just event handlers for the buttons that can be pressed by the user. Each event handler calls AppendToLog
(left buttons) or AppendToLogAndScroll()
(middle buttons) but uses a different text, line break characters and text color.
Further Documentation
The application is also documented using Doxygen tags. I have left over the PDF in the doc/latex subdirectory, but if you like, you can create the whole HTML and LaTeX-documentation using Doxygen. All you need to do is run "doxygen doxyfile
" in the main directory of the demo app using a Windows Command Console or Linux shell.
History
This is version 2 of the article.
- Version 2: Added functions
GetNumVisibleLines()
andAddToLogAnd Scroll()
. These functions implement robust auto-scrolling. - Version 1: Initial release. Published Oct 10, 2005.