MFC的文档/视图结构使我们的打印工作变得更加便捷,为了便于明晰打印流程,让我们了解一下MFC在背后“偷偷”为我们做了哪些工作。
1> 创建打印设备描述表并在打印结束后删除它
2> 调用StartDoc和EndDoc来开始和结束打印工作
3> 调用StartPage和EndPage来开始和结束每一页
在文档/视图结构的程序中实现打印的关键是一组CView类的虚函数,主框架要在打印处理的不同阶段调用他们,实际使用时我们可以根据需要覆盖这些函数,这里我建议用MFC的Class Wizard把下边的5个函数全部覆盖。
1> OnPreparePrinting
在设置打印参数时调用,可以给主框架提供打印页数和其他与打印有关的信息
2> OnBeginPrinting
在打印开始前调用,可以用来分配字体和其他打印需要的资源
3> OnPrepareDC
在每一页打印之前调用,可以用来指定视口原点位置并在OnDraw打印下页之前设置剪贴区域
4> OnPrint
在每一页打印时调用,可以用来打印页眉、页角以及其他没有用OnDraw或者不依赖OnDraw打印的页面元素
5> OnEndPrinting
打印结束后调用,可以用来释放OnBeginPrinting中分配的资源
实现MFC应用程序打印功能有两种方法,一种是让OnDraw函数既处理屏幕输出又处理打印输出;另一种是让OnDraw处理屏幕输出而让OnPrint处理打印输出。用OnDraw函数处理打印的话必然会添加很多打印特有的代码段,而且为了让打印功能更加完备,通常必需要在OnPrint函数中添加打印页眉、页角等代码,使得程序看起来比较凌乱。依我个人的经验,打印和屏幕输出有很多应该是不同的,比如在屏幕输出时我们可以设置很多背景和线条颜色,如果打印也这么设置的话必然会造成打印输出缓慢(要打印的象素多),有时打印机是黑白的,再多色彩打出来也就那么两三种颜色,得不偿失。当然打印图片得程序是个例外。我们通常更实际得把打印机输出得程序段放在OnPrint中,把屏幕输出程序段放在OnDraw中,我们这里仅介绍这种方法。
1. OnPreparePinting函数
BOOL OnPreparePrinting(CPrintInfo* pInfo)
{
pInfo->SetMaxPage(10);
return DoPreparePrinting(pInfo);
}
参数pInfo包含了很多打印工作参数的信息,包括最小和最大页数,默认为1和0xFFFF。0xFFFF告诉主框架最大页数还不知道。MFC会在打印对话框的To框中显示最大页编码。CPrintInfo类有很多函数设置打印参数,具体可参考MSDN。
注意:GetFromPage和GetToPage返回用户在“打印”对话框中选择的页码范围,由于是在DoPreparePrinting之后显示打印对话框,所以要注意在DoPreparePrinting函数之后调用他们。
2. OnBeginPrinting和OnEndPrinting函数
实际上打印的页数通常由页面大小来决定,而我们调用OnPreparePinting函数时通常是不知道的,如果在 OnPreparePinting函数中没有设置最大页数,可以在OnBeginPrinting函数中设置,传给OnBeginPrinting函数的是一个已经初始化完成的CPrintInfo结构,在OnBeginPrinting函数中可以调用CDC::GetDeviceCaps两次来确定可打印页区域的尺寸,一次用HORZRES参数调用,一次用VERTRES参数调用。
void CMyView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
{
CPrintDemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
int npageheight = pDC->GetDeviceCaps(VERTRES);
int npagewidth = pDC->GetDeviceCaps(HORZRES);
int nmaxpage = max(1,(pDoc->m_nDocLength+npageheight-1)/npageheight);
pInfo->SetMaxPage(nmaxpage);
}
注意:OnBeginPrinting中的pInfo结构中有一个m_rectDraw描述了可打印页面区域,但是OnBeginPrinting函数返回之前,该变量是不会被初始化的,也就是说不能在OnBeginPrinting函数中使用该变量。
此外,最好在OnBeginPrinting中创建字体和打印中要用到的其他GDI资源,OnEndPrinting函数时和OnBeginPrinting函数配对使用的,用来释放OnBeginPrinting函数创建的资源。
3. OnPrepareDC函数
如果在OnBeginPrinting中仍然无法知道要打印文档的页数,可以在打印每页前所调用的OnPrepareDC函数中设CPrintInfo结构的m_bContinuePrinting变量的值来执行打印时分页。m_bContinuePrinting=TRUE时继续打印,m_bContinuePrinting=FALSE时结束打印工作。如果不调用SetMaxPage函数设置最大页数,系统默认文档只有一页。所以如果由多页文档且页数不确定,我们就必须用m_bContinuePrinting的值来控制多页打印。
打印文档的每一页之前都会调用OnPrepareDC函数,另一个需要再该函数完成的功能是根据当前页编号计算新的视口原点以便OnDraw函数可以将当前页输出到打印机上,这里我们不做过多描述。
4. OnPrint函数
每一页打印时框架自动调用OnPrint函数,如果调用OnDraw函数完成打印输出,可以在此编写打印页眉和页角的代码;如果用OnPring函数来完成打印输出,就需要包含输出打印内容的程序代码。要想知道当前打印的是哪一页,可查询CPrintInfo的m_nCurPage。