Programming Microsoft Visual C++
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.
- Run AppWizard to generate \vcpp32\ex19b\ex19b. Select Single Document, and accept the defaults for all the other settings. The options and the default class names are shown here.
- Edit the StdAfx.h header file. You'll need to bring in the declarations for the MFC template collection classes. Add the following statement:
#include <afxtempl.h>
- Edit the ex19bDoc.h header file. In the EX19A example, the document data consists of strings stored in a CStringArray collection. Because we're using a template collection for ellipse rectangles, we'll need a typedef statement outside the class declaration, as shown here:
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.
- Edit the ex19bDoc.cpp implementation file. The overridden OnNew Document function initializes the ellipse array with some random values, and the Serialize function reads and writes the whole array. AppWizard generated the skeletons for both functions. You don't need a DeleteContents function because the CArray subscript operator writes a new CRect object on top of any existing one. Add the following boldface code:
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); }
- Edit the ex19bView.h header file. Use ClassView to add the member variable and two function prototypes listed below. ClassView will also generate skeletons for the functions in ex19bView.cpp.
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.
- Edit the OnDraw function in ex19bView.cpp. The overridden OnDraw function simply draws the bubbles in the view window. Add the boldface code shown here:
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]); } }
- Insert the OnPrepareDC function in ex19bView.cpp. The view class is not a scrolling view, so the mapping mode must be set in this function. Use ClassWizard to override the OnPrepareDC function, and then add the following boldface code:
void CEx19bView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { pDC->SetMapMode(MM_LOENGLISH); }
- Insert the OnPrint function in ex19bView.cpp. The CView default OnPrint function calls OnDraw. In this example, we want the printed output to be entirely different from the displayed output, so the OnPrint function must take care of the print output without calling OnDraw. OnPrint first sets the mapping mode to MM_TWIPS, and then it creates a fixed-pitch font. After printing the numeric contents of 12 m_ellipseArray elements, OnPrint deselects the font. You could have created the font once in OnBeginPrinting, but you wouldn't have noticed the increased efficiency. Use ClassWizard to override the OnPrint function, and then add the following boldface code:
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); }
- Edit the OnPreparePrinting function in ex19bView.cpp. The OnPreparePrinting function (whose skeleton is generated by AppWizard) computes the number of pages in the document and then communicates that value to the application framework through the SetMaxPage function. Add the following boldface code:
BOOL CEx19bView::OnPreparePrinting(CPrintInfo* pInfo) { CEx19bDoc* pDoc = GetDocument(); pInfo->SetMaxPage(pDoc->m_ellipseArray.GetUpperBound() / CEx19bDoc::nLinesPerPage + 1); return DoPreparePrinting(pInfo); }
- Insert the page header and footer functions in ex19bView.cpp. These private functions, called from OnPrint, print the page headers and the page footers. The page footer includes the page number, stored by OnPrint in the view class data member m_nPage. The CDC::GetTextExtent function provides the width of the page number so that it can be right-justified. Add the boldface code shown here:
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 }
- Build and test the application. For one set of random numbers, the bubble view window looks like this.
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.
Категории