Click here to Skip to main content
Click here to Skip to main content

Using RichEditCtrl to Display Formatted Logs

, 26 May 2011
Rate this:
Please Sign up or sign in to vote.
A simple demo to show you how to use the standard RichEditCtrl to print formatted text to a message/log window.
RichEditLog_Demo Screenshot

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.

The message log automatically scrolls to display the last lines added.

Targeted Audience

This article is for CRichEditCtrl beginners only.

Step 1: Insert a CRichEditCtrl into your Dialog

  1. 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).
  2. Add a member variable for the Rich Edit Control using the Class Wizard. Select "Control" as variable type. I used the name m_ctrlLog.
  3. Open the source file of your application and go to the InitInstance method. Insert the line AfxInitRichEdit2(); right after the AfxEnableControlContainer(); line.
  4. 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() and AddToLogAnd Scroll(). These functions implement robust auto-scrolling.
  • Version 1: Initial release. Published Oct 10, 2005.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

typke
Web Developer
Germany Germany
No Biography provided

Comments and Discussions

 
QuestionHow to change auto linefeed to manuall line feed when I get the rtf from the richeditctrl? Pinmembertiger5491014-May-13 19:00 
Questionfaster appending Pinmembervinaypeepl7-Oct-12 1:15 
Generalvertical scroll to end Pinmemberjinfd18-Jun-11 22:11 
GeneralRe: vertical scroll to end Pinmembertypke20-Jun-11 4:34 
Generalline breaks with word wrap code Pinmemberrickz657-Jun-11 19:11 
GeneralRe: line breaks with word wrap code Pinmembertypke8-Jun-11 5:09 
GeneralVery Nice! My 5 PinmemberSharjith26-May-11 8:16 
GeneralReally Good Pinmembermanish rastogi13-Feb-09 20:35 
Generalhelpful... Pinmemberauralius11-Jan-09 13:06 
GeneralA simple and useful article. 10x ! Pinmemberbogdan3474-Jan-09 6:03 
GeneralThanks. PinmemberMember 57525476-Dec-08 2:23 
GeneralThanks PinmemberSteve_Harris11-Mar-08 23:59 
QuestionRichEditCtrl PinmemberAshok Panchal3-Apr-07 3:24 
Generalcan't run on Win98 Pinmemberpeter lee sh14-Sep-06 22:55 
GeneralRe: can't run on Win98 Pinmembertypke17-Sep-06 20:50 
QuestionRe: can't run on Win98 Pinmemberpeter lee sh17-Sep-06 21:56 
GeneralRe: can't run on Win98 Pinmemberpeter lee sh17-Sep-06 22:12 
GeneralRe: can't run on Win98 Pinmembertypke18-Sep-06 20:55 
GeneralLittle improvement PinmemberMoFo25-Aug-06 3:11 
Generalvery helpful Pinmembertomei28-Apr-06 2:18 
GeneralRe: very helpful Pinmembertypke1-May-06 1:12 
QuestionChange Font? Pinmemberthompsons18-Apr-06 17:49 
AnswerRe: Change Font? Pinmembertypke18-Apr-06 21:13 
GeneralThis is not "sh*t" at all! PinmemberLeeeNN13-Feb-06 14:14 
GeneralThanks! Pinmembertp10027-Jan-06 3:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 26 May 2011
Article Copyright 2005 by typke
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid