Click here to Skip to main content
15,881,204 members
Articles / Desktop Programming / MFC
Article

How to print the content of a Rich Edit Control

Rate me:
Please Sign up or sign in to vote.
4.61/5 (14 votes)
26 Dec 2002CPOL2 min read 175.2K   2.5K   38   35
Rich Edit controls are great until you want to print the output. Help is at hand

Introduction

I see many questions about printing, when helping people on the VC++ forum here at CP, but the one thing I have never been able to help people with, was printing the content of a Rich Edit Control. So off I went to the documentation to try and do something about it.

So how did I do?

  • Yes, you can print a Rich Edit Control
  • But the print preview sucks

I will be continuing to look into the print preview problems with the Rich Edit Control, but in the meantime, I though I would make available my solution to actual printing.

What to do to get a Rich Edit Control to print?

A Rich Edit Control has built in support for printing, but it is covered by a number of functions which have to be used in the correct way to get output on your target printer DC. These 3 functions are:

  • SetTargetDevice()

    This function in effect attaches the printer DC to the Rich Edit control, until you do another call to this function passing NULL as the new HDC.

  • FormatRange()

    This procedure looks at the start/end characters provided and see what part of the control's content will be visible in the output range.

  • DisplayBand()

    This procedure actually does the plotting of the output.

What steps do I need to take?

First you need to determine how many pages of output you are going to require for your printout. This will depend on the control content and the printable area of the paper etc. My example assumes that the Rich Edit Control will print all its content and have all of every page to print to when generating output, so this is how I calculate the number of pages:

BOOL CRichEditPrintView::OnPreparePrinting(CPrintInfo* pInfo)
{
    CDC dc;
    CRect page;
    FORMATRANGE fmtRange;
    long lLineWidth;
    int last = 0;

    AfxGetApp()->CreatePrinterDC(dc);
    if (!dc.m_hDC)
    {
        TRACE("Failed to get printer DC\n");
        return FALSE;
    }
    dc.SaveDC();

    pInfo->SetMaxPage(0);
    // get the page size in twips (1440 twips/inch)
    page.left = 0;
    page.top = 0;
    page.right = ::MulDiv(dc.GetDeviceCaps(PHYSICALWIDTH), 
                    1440, dc.GetDeviceCaps(LOGPIXELSX));
    page.bottom = ::MulDiv(dc.GetDeviceCaps(PHYSICALHEIGHT), 
                    1440, dc.GetDeviceCaps(LOGPIXELSY));
    lLineWidth = ::MulDiv(dc.GetDeviceCaps(PHYSICALWIDTH), 
                    1440, dc.GetDeviceCaps(LOGPIXELSX));
    // setup the format range attributes
    fmtRange.hdc = dc.m_hDC;
    fmtRange.hdcTarget = dc.m_hAttribDC;
    fmtRange.rc = page;
    fmtRange.rcPage = page;

    // determine the correct output for this page
    m_Control.SetTargetDevice(dc, lLineWidth);
    while (last < m_Control.GetTextLength())
    {
        fmtRange.chrg.cpMin = last;
        fmtRange.chrg.cpMax = -1;
        // measure the data that goes on this page
        
        // just measuring, not displaying
        last = m_Control.FormatRange(&fmtRange, FALSE);
        fmtRange.chrg.cpMax = last;
        pInfo->SetMaxPage(pInfo->GetMaxPage() + 1);
    }
    m_Control.FormatRange(NULL, FALSE);
    // release the cached DC information stored in SetTargetDevice
    dc.RestoreDC(-1);
    dc.DeleteDC();
    return DoPreparePrinting(pInfo);
}

This should give us the correct number of pages of output for the content.

Do the OnPrint() version

The actual version that does the printing is very similar except that:

  • It skips over pages already printed.
  • It prints the output.

The code looks like:

void CRichEditPrintView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
    long lLineWidth = ::MulDiv(pDC->GetDeviceCaps(PHYSICALWIDTH), 
                            1440, pDC->GetDeviceCaps(LOGPIXELSX));
    FORMATRANGE fmtRange;
    CRect rect;
    CRect page;
    int last = 0;

    // get the page size in twips (1440 twips/inch)
    page.left = 0;
    page.top = 0;
    page.right = ::MulDiv(pDC->GetDeviceCaps(PHYSICALWIDTH), 
                        1440, pDC->GetDeviceCaps(LOGPIXELSX));
    page.bottom = ::MulDiv(pDC->GetDeviceCaps(PHYSICALHEIGHT), 
                        1440, pDC->GetDeviceCaps(LOGPIXELSY));
    // for our example, the rect is the page
    rect = page;

    // setup the format range attributes
    fmtRange.hdc = pDC->m_hDC;
    fmtRange.hdcTarget = pDC->m_hAttribDC;
    fmtRange.rc = rect;
    fmtRange.rcPage = page;

    pDC->SaveDC();
    // determine the correct output for this page
    m_Control.SetTargetDevice(*pDC, lLineWidth);
    for (UINT i = 0 ; i < pInfo->m_nCurPage ; i++)
    {
        fmtRange.chrg.cpMin = last;
        fmtRange.chrg.cpMax = -1;
        // measure the data that goes on this page
        
        // just measuring, not displaying
        last = m_Control.FormatRange(&fmtRange, TRUE);
        fmtRange.chrg.cpMax = last;
        // when we drop out of the loop, we should 
        //print the correct part of the output for the current page
    }
    m_Control.DisplayBand(&rect);    
    m_Control.FormatRange(NULL, FALSE);
    // release the cached DC information stored in SetTargetDevice
    pDC->RestoreDC(-1);
}

And that's it basically.

Problems, problems, problems

As mentioned earlier, the print preview of the output sucks due to the Rich Edit Control not scaling the font(s) and spacing the text correctly for the Screen DC used during the preview process. I will be continuing to look into this. My best guess at the moment may be to implement a complete RTF output library, that will be able to plot the RTF text correctly for preview and print, but its a lot of work.

Enjoy - or not when it comes to Rich Edit Controls.

License

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


Written By
Software Developer (Senior) Sirius Analytical Instruments
United Kingdom United Kingdom
A research and development programmer working for a pharmaceutical instrument company for the past 17 years.

I am one of those lucky people who enjoys his work and spends more time than he should either doing work or reseaching new stuff. I can also be found on playing DDO on the Cannith server (Send a tell to "Maetrim" who is my current main)

I am also a keep fit fanatic, doing cross country running and am seriously into [url]http://www.ryushinkan.co.uk/[/url] Karate at this time of my life, training from 4-6 times a week and recently achieved my 1st Dan after 6 years.

Comments and Discussions

 
QuestionPrinting selected text in Rich Edit Control Pin
dr dirt22-Feb-21 11:49
dr dirt22-Feb-21 11:49 
QuestionPrinting multipage rich edit control contents clips through lines Pin
Shaown.Sarker15-May-12 23:35
Shaown.Sarker15-May-12 23:35 
QuestionRTF to Image Pin
Horia Tudosie30-Sep-11 13:28
Horia Tudosie30-Sep-11 13:28 
GeneralProblem with page breaks and less and less printing per page - solved. Pin
Phil Outram19-Jul-10 4:37
Phil Outram19-Jul-10 4:37 
GeneralFix problem "Failed to get printer DC" Pin
HN123455-Jan-08 7:31
HN123455-Jan-08 7:31 
Use the following code to create the device context in OnPreparePrinting
PRINTDLG pd;<br />
if ( !AfxGetApp()->GetPrinterDeviceDefaults(&pd) )<br />
    return FALSE;<br />
<br />
HDC hdc = AfxCreateDC(pd.hDevNames, pd.hDevMode);<br />
if ( !hdc )<br />
    return FALSE;<br />
<br />
dc.Attach(hdc);<br />

instead
AfxGetApp()->CreatePrinterDC(dc);

Dont forget to add
#include <afxpriv.h>
in stdafx.h

Smile | :) Herbert
GeneralCorrect PrintPreview Pin
HN123455-Jan-08 6:28
HN123455-Jan-08 6:28 
QuestionPrint listView items on A4 paper in Visual C++ Express Edition Pin
chrisliando14-Nov-07 13:28
chrisliando14-Nov-07 13:28 
GeneralFor Those of You Using Rich Edit Control 2.0 Pin
ahuipersonal27-Dec-06 8:36
ahuipersonal27-Dec-06 8:36 
Generali want to print dialog base application richedit data Pin
Chetan Sheladiya9-Jul-06 19:25
professionalChetan Sheladiya9-Jul-06 19:25 
GeneralI can't get correct index of last printable text Pin
icewolf91119-Dec-05 15:47
icewolf91119-Dec-05 15:47 
GeneralEscape Sequence Pin
tjuentgen16-Feb-05 1:29
tjuentgen16-Feb-05 1:29 
GeneralTrying to Get the Print of RTF control Pin
Sajal Rastogi8-Jul-04 21:25
Sajal Rastogi8-Jul-04 21:25 
GeneralRe: Trying to Get the Print of RTF control Pin
sunshimin29-May-05 20:45
sunshimin29-May-05 20:45 
AnswerRe: Trying to Get the Print of RTF control Pin
john_o_williams5-Sep-06 2:42
john_o_williams5-Sep-06 2:42 
QuestionAnd with a richtext ? Pin
pjonas2-Apr-04 1:32
pjonas2-Apr-04 1:32 
QuestionAll colors to black? Pin
Gernot Frisch2-Feb-04 2:02
Gernot Frisch2-Feb-04 2:02 
QuestionNone of this is need if the control is properly initialized? Pin
MarcK10-Sep-03 21:00
MarcK10-Sep-03 21:00 
AnswerRe: None of this is need if the control is properly initialized? Pin
CodeBrain11-Sep-03 0:42
CodeBrain11-Sep-03 0:42 
GeneralSolution for the preview problem Pin
CodeBrain5-Sep-03 1:11
CodeBrain5-Sep-03 1:11 
GeneralPrinting in the CRichEditView class Pin
CodeBrain4-Sep-03 22:27
CodeBrain4-Sep-03 22:27 
GeneralOverlapping pages Pin
cristeap8-Jun-03 11:28
cristeap8-Jun-03 11:28 
GeneralRe: Overlapping pages Pin
cristeap8-Jun-03 11:34
cristeap8-Jun-03 11:34 
Generalcached dc Pin
Beer2-Jun-03 15:08
Beer2-Jun-03 15:08 
GeneralRe: cached dc Pin
Beer2-Jun-03 15:48
Beer2-Jun-03 15:48 
Generalis it Posible to Print richtext with in a given rectangle area Pin
Balaji200028-May-03 6:33
Balaji200028-May-03 6:33 

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

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