摘要
本文首先介绍了利用MFC提供的文档视图框架来实现一个打印程序,并实现打印预览,在此基础上,同时通过对MFC源代码的深入探讨,提出了利用该方法在对话框上用MFC实现打印功能,结果表明,利用MFC实现打印不仅方便,而且功能很强大,能够根据不同的需求很方便的打印出所需要的格式。本文还实现了一个在对话框中利用MFC实现打印功能的一个框架结构,对于使用者只要使用该结构就可以按照自己的要求打印任何内容。
关键词:Visual C++ ,MFC,对话框, 打印 ,打印预览
引言
打印程序的编写在windows程序设计中非常有用,针对不同的用户需要,通常用sdk方式实现打印代码量比较大,而且要对打印流程的底层有非常清楚的了解,需要一个程序员有非常深入的打印方面的知识,利用MFC提供的文档视图结构,不但可以实现一些常用的标准界面元素,把数据的处理的界面的处理分离出来,而且其提供的打印功能更是方便快捷,功能强大。打印程序的编写本质是是一种GDI绘图,只是绘图的对象是在打印机的设备描述表,如果对于屏幕的GDI绘图比较熟悉的读者,相信掌握打印程序的编写应该比较容易。
1、文档视图结构的程序的打印程序的编写
通常情况下,一个结构组织的比较好的MFC程序是基于文档视图结构的,这一框架结构给我们提供了很多功能,比如菜单,注册表的关联,文件类型的注册,打印功能,只要我们善于发掘,这些都可以为我们所用,但我们现在只关心如何使用MFC提供的结构来实现打印功能。
在编写打印程序之前,有必要先介绍一下MFC的框架结构,其中的文档视图结构又是这个框架的重点,我们通过分析MFC实现的视图类的原代码就可以看到一个打印程序的执行流程。读者也可以看侯俊杰的《深入浅出MFC》,上面有关于MFC打印的详细流程解释,下面是MFC的打印的函数的实现,该函数名为OnFilePrint它不是一个虚函数,而是响应缺省的COMMAND消息的处理函数,因为MFC提供了向导生成的菜单和工具栏,关于打印的命令ID为ID_FILE_PRINT ,而在视图类的MessageMap里有这样一项,ON_COMMAND (ID_FILE_PRINT, CView::OnFilePrint),因此实际使用的过程中可以不用原来的ID, 而使用自己的ID如ID_MYPRINT,再在MessageMap里加入ON_COMMAND (ID_MYPRINT, CView::OnFilePrint)即可完成原来一样的功能。ViewPrnt.cpp中有CView的OnFilePrint的函数的具体实现,ViewPrnt.cpp的位置读者自己用windows查找就能找到,这是MFC的源代码,本文把其中的主要代码列出放在下面,直接看下面的分析:
void CView::OnFilePrint()
{
// get default print info
if (OnPreparePrinting(&printInfo))
{
if (dlg.DoModal() != IDOK)
return;
}
OnBeginPrinting(&dcPrint, &printInfo);
OnPrepareDC(&dcPrint, &printInfo);
OnPrint(&dcPrint, &printInfo);
OnEndPrinting(&dcPrint, &printInfo); // clean up after printing
}
其中红色代码行为可以重载的虚函数,根据不同的用户,其内容会不同。对于 OnPreparePrinting() 函数的具体内容必须有 return DoPreparePrinting(pInfo);这是在一个打印过程中最先调用的。当然也可以包含一些其它的打印初始化操作。我们最主要的是要重载三个函数:
OnBeginPrinting();
OnPrint();
OnEndPrinting();
而以 OnPrint 最为复杂,它是我们要写大量代码实现我们打印功能的地方。对于默认的OnPrint实现是调用CView的OnDraw,也就是和绘制视图类的客户区的内容完全相同的方法来在打印机上绘图。实际中我们在两种地方绘图的内容是完全不同的,可能用户在客户区绘的是一个曲线,而在打印机上要绘制表格和数据。OnPrint(CDC* pDC, CPrintInfo* pInfo)的第二个参数是一个CPrintInfo类型的指针,我们可以从这个指针指向的对象中获得很多信息,如总共的页数,当前的页数,这在打印页眉页脚时可能是很有用的信息。CPrintInfo的定义如下:
struct struct CPrintInfo // Printing information structure
{
CPrintInfo();
~CPrintInfo();
CPrintDialog* m_pPD; // pointer to print dialog
BOOL m_bDocObject; // TRUE if printing by IPrint interface
BOOL m_bPreview; // TRUE if in preview mode
BOOL m_bDirect; // TRUE if bypassing Print Dialog
BOOL m_bContinuePrinting;// set to FALSE to prematurely end printing
UINT m_nCurPage; // Current page
UINT m_nNumPreviewPages; // Desired number of preview pages
CString m_strPageDesc; // Format string for page number display
LPVOID m_lpUserData; // pointer to user created struct
CRect m_rectDraw; // rectangle defining current usable page area
// these only valid if m_bDocObject
UINT m_nOffsetPage; // offset of first page in combined IPrint job
DWORD m_dwFlags; // flags passed to IPrint::Print
void SetMinPage(UINT nMinPage);
void SetMaxPage(UINT nMaxPage);
UINT GetMinPage() const;
UINT GetMaxPage() const;
UINT GetFromPage() const;
UINT GetToPage() const;
UINT GetOffsetPage() const;
};
OnBeginPrinting()通常用来设定要打印的总页数,以及一些和页面尺寸有关的初始化工作,在OnBeginPrinting()中设定打印的页数是必要的,默认的页数是只有一页,如果开发人员打印的页数大于1,则必须在此函数中设定打印的页数。然后在OnPrint(CDC* pDC, CPrintInfo* pInfo)中用pInfo-> m_nCurPage获取当前的页码,根据当前的页码打印该页相应的内容。OnEndPrinting用来释放在OnBeginPrinting中申请的资源,如果没有申请,则不需重载该函数。
关于打印预览只需要将自己的执行打印预览功能的命令ID和CView::OnFilePrintPreview关联起来就行了,具体方法是在用户的视图类的MessageMap中加入:
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview);
其中ID_FILE_PRINT_PREVIEW是默认的ID,开发人员也可以使用自己的ID。其实只要重载了OnPrint函数,在打印和打印预览中就可以重用该函数了。到现在为止,相信读者已经对利用MFC的文档视图结构来实现一个包含打印和打印预览功能的程序有了一个总体的认识了,本文还针对该方法给出了一个示例代码,代码来自Jeff Prosise 的《MFC windows程序设计》,见参考文献[1]。
2、没有文档视图结构的程序中利用MFC进行打印程序的编写
如果程序不是文档视图结构的,我们要使用MFC来进行打印,则可以通过建立一个虚拟的文档视图结构来进行打印,其实MFC的打印的强大功能是在CView里提供的,而CView类的对象是一个子窗口,它必须是某一个框架窗口的子窗口,而在对话框程序中,我们只需要打