In this example, the document contains an array of 50 CRect objects that define circles. The circles are randomly positioned in a 6-by-6-inch area and have random diameters of as much as 0.5 inch. The circles, when drawn on the display, look like two-dimensional simulations of soap bubbles. Instead of drawing the circles on the printer, the application prints the corresponding CRect coordinates in numeric form, 12 to a page, with headers and footers.

#include <afxtempl.h>
typedef CArray<CRect, CRect&> CRectArray;
Next add the following public data members to the ex19bDoc.h header file:
public:
enum { nLinesPerPage = 12 };
enum { nMaxEllipses = 50 };
CRectArray m_ellipseArray;
The two enumerations are object-oriented replacements for #defines.
BOOL CEx19bDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
int n1, n2, n3;
// Make 50 random circles
srand((unsigned) time(NULL));
m_ellipseArray.SetSize(nMaxEllipses);
for (int i = 0; i < nMaxEllipses; i++) {
n1 = rand() * 600 / RAND_MAX;
n2 = rand() * 600 / RAND_MAX;
n3 = rand() * 50 / RAND_MAX;
m_ellipseArray[i] = CRect(n1, -n2, n1 + n3, -(n2 + n3));
}
return TRUE;
}
void CEx19bDoc::Serialize(CArchive& ar)
{
m_ellipseArray.Serialize(ar);
}
public:
int m_nPage;
private:
void PrintPageHeader(CDC *pDC);
void PrintPageFooter(CDC *pDC);
The m_nPage data member holds the document's current page number for printing. The private functions are for the header and footer subroutines.
void CEx19bView::OnDraw(CDC* pDC)
{
int i, j;
CEx19bDoc* pDoc = GetDocument();
j = pDoc->m_ellipseArray.GetUpperBound();
for (i = 0; i < j; i++) {
pDC->Ellipse(pDoc->m_ellipseArray[i]);
}
}
void CEx19bView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
pDC->SetMapMode(MM_LOENGLISH);
}
void CEx19bView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
int i, nStart, nEnd, nHeight;
CString str;
CPoint point(720, -1440);
CFont font;
TEXTMETRIC tm;
pDC->SetMapMode(MM_TWIPS);
CEx19bDoc* pDoc = GetDocument();
m_nPage = pInfo->m_nCurPage; // for PrintPageFooter's benefit
nStart = (m_nPage - 1) * CEx19bDoc::nLinesPerPage;
nEnd = nStart + CEx19bDoc::nLinesPerPage;
// 14-point fixed-pitch font
font.CreateFont(-280, 0, 0, 0, 400, FALSE, FALSE,
0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_MODERN, "Courier New");
// Courier New is a TrueType font
CFont* pOldFont = (CFont*) (pDC->SelectObject(&font));
PrintPageHeader(pDC);
pDC->GetTextMetrics(&tm);
nHeight = tm.tmHeight + tm.tmExternalLeading;
for (i = nStart; i < nEnd; i++) {
if (i > pDoc->m_ellipseArray.GetUpperBound()) {
break;
}
str.Format("%6d %6d %6d %6d %6d", i + 1,
pDoc->m_ellipseArray[i].left,
pDoc->m_ellipseArray[i].top,
pDoc->m_ellipseArray[i].right,
pDoc->m_ellipseArray[i].bottom);
point.y -= nHeight;
pDC->TextOut(point.x, point.y, str);
}
PrintPageFooter(pDC);
pDC->SelectObject(pOldFont);
}
BOOL CEx19bView::OnPreparePrinting(CPrintInfo* pInfo)
{
CEx19bDoc* pDoc = GetDocument();
pInfo->SetMaxPage(pDoc->m_ellipseArray.GetUpperBound() /
CEx19bDoc::nLinesPerPage + 1);
return DoPreparePrinting(pInfo);
}
void CEx19bView::PrintPageHeader(CDC* pDC)
{
CString str;
CPoint point(0, 0);
pDC->TextOut(point.x, point.y, "Bubble Report");
point += CSize(720, -720);
str.Format("%6.6s %6.6s %6.6s %6.6s %6.6s",
"Index", "Left", "Top", "Right", "Bottom");
pDC->TextOut(point.x, point.y, str);
}
void CEx19bView::PrintPageFooter(CDC* pDC)
{
CString str;
CPoint point(0, -14400); // Move 10 inches down
CEx19bDoc* pDoc = GetDocument();
str.Format("Document %s", (LPCSTR) pDoc->GetTitle());
pDC->TextOut(point.x, point.y, str);
str.Format("Page %d", m_nPage);
CSize size = pDC->GetTextExtent(str);
point.x += 11520 - size.cx;
pDC->TextOut(point.x, point.y, str); // right-justified
}
Each time you choose New from the File menu, you should see a different picture. In Print Preview, the first page of the output should look like this.
With the Print dialog, you can specify any range of pages to print.