A document is not a physical object. It is an electronic representation of the result of an application. Because it is not physical, it doesn’t have dimensions: it has neither a width nor a length. On the other hand, a page that is part of a document has dimensions. When printing, there are standard dimensions that the printer will follow.
A document has and must have at least one page. A document can also have more than one page:
In the same way, a document can have as many pages as necessary:
Practical Learning: Introducing the Document and Pages
|
|
- To start a new application, on the main menu of Microsoft Visual C++, click File -> New -> Project…
- In the Templates section of the New Project dialog box, click MFC Application
- In the Name box, type DepartmentStore2 and click OK
- Click Application Type and, in the right frame, click Single Document
- In the left frame, click Document Template Strings and, in the Main Frame
Caption, change the string to Department Store
- In the left frame, click Generated Classes and make the following changes:
Class Name
|
.h File |
.cpp File |
Base Class
|
CExerciseView
|
ExerciseView.h
|
ExerciseView.cpp
|
CScrollView
|
CExerciseApp
|
|
|
CWinApp
|
CExerciseDoc
|
ExerciseDoc.h
|
ExerciseDoc.cpp
|
CDocument
|
- Click Finish
- Copy each of these pictures
|
Cover1.bmp
|
|
|
Dress1.bmp
|
Dress2.bmp
|
|
|
Dress3.bmp
|
Dress4.bmp
|
|
|
Dress5.bmp
|
Dress6.bmp
|
- Paste them in the res folder of the current project
- On the main menu, click Project -> Add Resource…
- In the Add Resource dialog box, click Import...
- Locate the res sub-folder of the current project, click Cover1.bmp
- Press and hold Ctrl
- Click Dress1.bmp, Dress2.bmp, Dress3.bmp, Dress4.bmp, Dress5.bmp, and Dress6.bmp
- Release Ctrl and click Open
- In the Resource View, expand the Bitmap folder, double-click each item and, in the Properties window, change its ID as follows:
Filename
|
ID
|
res/Cover1.bmp
|
IDB_COVER
|
res/Dress1.bmp
|
IDB_DRESS1
|
res/Dress2.bmp
|
IDB_DRESS2
|
res/Dress3.bmp
|
IDB_DRESS3
|
res/Dress4.bmp
|
IDB_DRESS4
|
res/Dress5.bmp
|
IDB_DRESS5
|
res/Dress6.bmp
|
IDB_DRESS6
|
- In the Class View, expand DepartmentStore2, expand CExerciseView, and double-click OnInitialUpdate
- Change it as follows:
void CExerciseView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CSize sizeTotal;
// TODO: calculate the total size of this view
sizeTotal.cx = 500;
sizeTotal.cy = 1360;
SetScrollSizes(MM_TEXT, sizeTotal);
}
|
- In the Class View, expand CmainFrame and double-click OnCreate
- Change the event as follows:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.cx = 450;
cs.cy = 600;
cs.style &= ~FWS_ADDTOTITLE;
return TRUE;
}
|
- Save all
Introduction to Document/View Printing
|
|
One of the primary ways Microsoft reduces its complexity of printing is through device independence. This means that you should worry less with the type of device used to print: you don’t have to care what type of printer or machine would be used to print a document of your application. What you have left to do is the drawing side of the document. You have two main approaches: using the MFC Application or manually implementing the document/view architecture of the MFC library.
As mentioned in the previous sections, if you use the MFC Application and decide to create a
CView-based application, the wizard would suggest support for printing. If you accept it, it would add a Print, a Print Preview, and a Print Setup options. As the wizard is writing the primary code for your application, it would add code for three events:
OnPreparePrinting, OnBeginPrinting, and OnEndPrinting:
BOOL CExerciseView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CExerciseView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CExerciseView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
As you may know by now, the user typically launches printing by opening the Print dialog box that is equipped with various options and then
clicking OK. To control how these options are presented to the user, the view class fires the
OnPreparePrinting event. Its syntax is:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
If you are manually creating your application, make sure you add this event. As you can see from the above lines, the primary code written by the wizard serves only as a placeholder.
This event takes as argument a CPrintInfo object. Notice that it is passed as a pointer. This is for two good reasons. If you access the argument, it can give you information about the print job, information that may have been stored in the
CPrintInfo object. In the same way, you can use the argument to make changes to the print job. After making such changes, call the
CView::DoPreparePrinting() method and pass it the modified CPrintInfo object. The syntax of this method is:
BOOL DoPreparePrinting(CPrintInfo* pInfo);
The CView::OnPreparePrinting() event fires when the user initiates printing but before the actual printing occurs. This is a good place to set some options on the Print dialog box. There are two ways you can do this. You can directly use the
pInfo object because the CPrintInfo structure has a member variable named
m_pPD that is of type CPrintDialog. Another technique consists of creating your own
CPrintDialog object, define it as you wish, and then assigning it to the
m_pPD member of the pInfo argument. Here is an example:
BOOL CExerciseView::OnPreparePrinting(CPrintInfo* pInfo)
{
CPrintDialog *dlg = new CPrintDialog(FALSE, PD_PAGENUMS);
pInfo->m_pPD = dlg;
pInfo->SetMinPage(1);
pInfo->SetMaxPage(14);
// default preparation
return DoPreparePrinting(pInfo);
}
Practical Learning: Preparing to Print
|
|
-
In the Class View and under the CExerciseView node, double-click OnPreparePrinting and change it as follows:
BOOL CExerciseView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
pInfo->SetMaxPage(2);
return DoPreparePrinting(pInfo);
}
|
-
Save all
Document Printing Preparation
|
|
Once the Print dialog box displays, the user can review, accept or make changes on it, and then click OK to print. Of course, the user can click Cancel to give up. Once the user clicks OK, before the job gets to the device, you must prepare the tools that would be used. To assist you with making the preparation for the actual printing, the view class fires an
OnBeginPrinting event:
The syntax of the OnBeginPrinting event is:
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
The pDC argument is the device context of the printer.
The pInfo is used to describe the print job. If you are manually creating
your view-based application, you should override this event. If you use the
MFC Application, the wizard can create the skeleton code for you.
Because the OnBeginPrinting event is fired before the actual printing starts, you can use it to initialize the GDI tools that would be used to draw on the printed sheet. To make sure that these tools are available to other events, you should have declared them globally.
Practical Learning: Beginning to Print
|
|
- In the Class View, double-click the CExerciseView node and declare two private CFont pointers as follows:
private:
CFont *fntTitle1;
CFont *fntTitle2;
};
|
- In the Class View, under CExerciseView, double-click OnBeginPrinting and change it as follows:
void CExerciseView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
this->fntTitle1 = new CFont;
fntTitle1->CreateFont(60, 40, 0, 0,
FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,
_T("Times New Roman"));
this->fntTitle2 = new CFont;
fntTitle2->CreateFont(100, 50, 900, 0,
FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,
_T("Times New Roman"));
}
|
- Save all
Device Context Preparation |
|
After allocating GDI resources that would be used to draw,
you can prepare the printer’s device context. To assist you with this, you can
use the OnPrepareDC event of the view. The syntax of this event is:
virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);
The pDC argument represents the device context of the printer. The
pInfo object contains a description of the print job such as the number of pages.
When preparing the printer’s device context, you can examine the values of the
pInfo argument here. During printing, the device will check the information in the
pInfo object. For example, if pInfo doesn’t specify the number of pages, the printer will consider that the document contains only one page. In this case, if the document contains more than one, the first page would be printed, the
CPrintInfo::m_pContinuePrinting value would be set to FALSE, and the printing would stop.
While a printing job is going on, the page that is being printed at a particular time is referred to as the current page and it is represented by the
CPrintInfo::m_nCurPage value. Using the
OnPrepareDC() event, you can continually check the value of the CPrintInfo::m_nCurPage value. When the printer gets to the last page, the value of this member would be set to 1. Once you find this out, you can set the
CPrintInfo::m_pContinuePrinting value to FALSE.
The actual printing occurs in the CView::OnPrint() event. Its syntax is:
virtual void OnPrint(CDC* pDC, CPrintInfo* pInfo);
The pDC object is the device context of the printer,
the CDC on which the contents of the document would be printed. The pInfo object
contains a description of the print job.
While the OnPreparePrinting event is fired when a
document is sent to the printer, the OnPrint event is fired for each page to be printed:
You can use the OnPrint event to format a page the way
you want. For example, you can create a top section referred to as the header
and/or a bottom section referred to as the footer.
As stated already, the printing of a page is performed in
response to the CView::OnPrint event. At a particular time, if you
want to find out whether a print job is currently occurring, you can call the
CDC::IsPrinting() method. If a printing job is going on, this method
returns TRUE. Otherwise, it returns FALSE.
Practical Learning: Printing
|
|
-
In the Class View, click CExerciseView and, in the Overrides section of the Properties window, click the arrow of the OnPrint item to select <Add> OnPrint
-
Implement the event as follows:
void CExerciseView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
// TODO: Add your specialized code here and/or call the base class
pDC->SetMapMode(MM_ISOTROPIC);
pDC->SetWindowExt(500, 500);
pDC->SetViewportExt(4500, 6500);
if( pInfo->m_nCurPage == 1 )
{
CBitmap bmpCover;
CDC memDCCover;
CBitmap *bmpOldCover;
bmpCover.LoadBitmap(IDB_COVER);
memDCCover.CreateCompatibleDC(pDC);
bmpOldCover = memDCCover.SelectObject(&bmpCover);
pDC->SetBkMode(TRANSPARENT);
pDC->BitBlt(100, 60, 400, 560, &memDCCover, 0, 0, SRCCOPY);
pDC->SelectObject(bmpOldCover);
CFont *fntOld = pDC->SelectObject(fntTitle1);
pDC->TextOut(10, 10, "Collection", 10);
fntOld = pDC->SelectObject(fntTitle2);
pDC->TextOut(5, 400, "Spring", 6);
pDC->SelectObject(fntOld);
}
else if( pInfo->m_nCurPage == 2 )
{
CBitmap bmpDress1, bmpDress2, bmpDress3,
bmpDress4, bmpDress5, bmpDress6;
CDC memDCDress1, memDCDress2, memDCDress3,
memDCDress4, memDCDress5, memDCDress6;
CBitmap *pOldDress;
bmpDress1.LoadBitmap(IDB_DRESS1);
bmpDress2.LoadBitmap(IDB_DRESS2);
bmpDress3.LoadBitmap(IDB_DRESS3);
bmpDress4.LoadBitmap(IDB_DRESS4);
bmpDress5.LoadBitmap(IDB_DRESS5);
bmpDress6.LoadBitmap(IDB_DRESS6);
memDCDress1.CreateCompatibleDC(pDC);
memDCDress2.CreateCompatibleDC(pDC);
memDCDress3.CreateCompatibleDC(pDC);
memDCDress4.CreateCompatibleDC(pDC);
memDCDress5.CreateCompatibleDC(pDC);
memDCDress6.CreateCompatibleDC(pDC);
pOldDress = memDCDress1.SelectObject(&bmpDress1);
pDC->BitBlt(10, 10, 94, 200, &memDCDress1, 0, 0, SRCCOPY);
pOldDress = memDCDress2.SelectObject(&bmpDress2);
pDC->BitBlt(360, 10, 113, 200, &memDCDress2, 0, 0, SRCCOPY);
pOldDress = memDCDress3.SelectObject(&bmpDress3);
pDC->BitBlt(10, 220, 148, 200, &memDCDress3, 0, 0, SRCCOPY);
pOldDress = memDCDress4.SelectObject(&bmpDress4);
pDC->BitBlt(380, 220, 78, 200, &memDCDress4, 0, 0, SRCCOPY);
pOldDress = memDCDress5.SelectObject(&bmpDress5);
pDC->BitBlt(10, 440, 100, 200, &memDCDress5, 0, 0, SRCCOPY);
pOldDress = memDCDress6.SelectObject(&bmpDress6);
pDC->BitBlt(360, 440, 143, 200, &memDCDress6, 0, 0, SRCCOPY);
pDC->SelectObject(pOldDress);
}
CScrollView::OnPrint(pDC, pInfo);
}
|
-
In the Methods combo box, select OnDraw and change it as follows:
void CExerciseView::OnDraw(CDC* pDC)
{
CExerciseDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
if( !pDC->IsPrinting() )
{
CBitmap bmpCover,
bmpDress1, bmpDress2, bmpDress3,
bmpDress4, bmpDress5, bmpDress6;
CDC memDCCover,
memDCDress1, memDCDress2, memDCDress3,
memDCDress4, memDCDress5, memDCDress6;
bmpCover.LoadBitmap(IDB_COVER);
bmpDress1.LoadBitmap(IDB_DRESS1);
bmpDress2.LoadBitmap(IDB_DRESS2);
bmpDress3.LoadBitmap(IDB_DRESS3);
bmpDress4.LoadBitmap(IDB_DRESS4);
bmpDress5.LoadBitmap(IDB_DRESS5);
bmpDress6.LoadBitmap(IDB_DRESS6);
memDCCover.CreateCompatibleDC(pDC);
memDCDress1.CreateCompatibleDC(pDC);
memDCDress2.CreateCompatibleDC(pDC);
memDCDress3.CreateCompatibleDC(pDC);
memDCDress4.CreateCompatibleDC(pDC);
memDCDress5.CreateCompatibleDC(pDC);
memDCDress6.CreateCompatibleDC(pDC);
CBitmap *bmpOld = memDCCover.SelectObject(&bmpCover);
pDC->BitBlt(80, 60, 400, 560, &memDCCover, 0, 0, SRCCOPY);
bmpOld = memDCDress1.SelectObject(&bmpDress1);
pDC->BitBlt(10, 680, 94, 200, &memDCDress1, 0, 0, SRCCOPY);
bmpOld = memDCDress2.SelectObject(&bmpDress2);
pDC->BitBlt(360, 680, 113, 200, &memDCDress2, 0, 0, SRCCOPY);
bmpOld = memDCDress3.SelectObject(&bmpDress3);
pDC->BitBlt(10, 900, 148, 200, &memDCDress3, 0, 0, SRCCOPY);
bmpOld = memDCDress4.SelectObject(&bmpDress4);
pDC->BitBlt(380, 900, 78, 200, &memDCDress4, 0, 0, SRCCOPY);
bmpOld = memDCDress5.SelectObject(&bmpDress5);
pDC->BitBlt(10, 1150, 100, 200, &memDCDress5, 0, 0, SRCCOPY);
bmpOld = memDCDress6.SelectObject(&bmpDress6);
pDC->BitBlt(340, 1150, 143, 200, &memDCDress6, 0, 0, SRCCOPY);
CFont fntVertical;
CFont fntHorizontal;
CFont *pFont;
pDC->SetBkMode(TRANSPARENT);
fntHorizontal.CreateFont(60, 40, 0, 0,
FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,
_T("Times New Roman"));
pFont = pDC->SelectObject(&fntHorizontal);
pDC->TextOut(10, 10, "Collection", 10);
fntVertical.CreateFont(100, 50, 900, 0,
FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,
_T("Times New Roman"));
pFont = pDC->SelectObject(&fntVertical);
pDC->TextOut(5, 400, "Spring", 6);
pDC->SelectObject(fntVertical);
fntVertical.DeleteObject();
fntHorizontal.DeleteObject();
}
}
|
-
Save all
Document Printing Finalization |
|
Eventually, after a print job has been performed, the view would fire an OnEndPrinting
event:
Its syntax is:
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
This event takes the same arguments as its counterpart the
OnBeginPrinting. This event is a good place to free the GDI resources
that were allocated.
Practical Learning: Finalizing a Printing Job
|
|
-
In the Class View, under the CExerciseView node, double-click OnEndPrinting and change it as follows:
void CExerciseView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
delete fntTitle1;
delete fntTitle2;
}
|
-
Execute the application and print its document
-
Close the application
|
|