VC++对话框程序打印及打印预览的实现(三)
本⽂⾸先介绍了利⽤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 structCPrintInfo // 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类的对象是⼀个⼦窗⼝,它必须是某⼀个框架窗⼝的⼦窗⼝,⽽在对话框程序中,我们只需要打印,⽽不需要显⽰这个框架窗⼝和视图。我们以按下按钮"打印"来执⾏打印程序,例如按钮为ID为IDC_PNT,消息相应函数为OnPnt(),即:
ON_BN_CLICKED(IDC_PNT, OnPnt);
需要在OnPnt中建⽴⼀个框架窗⼝,同时使某个CView类的对象为该窗⼝的⼦窗⼝。因此笔者建⽴了两个类,⼀个为框架窗⼝类CPrintFrame,另⼀个为CPrintView,具体的内容见⽰例代码。在新建⼀个⽤于打印的虚拟框架窗⼝时,需要将执⾏打印的对话框的指针传给框架窗⼝,这以便在对话框来响应WM_BEGIN_PRINTING和WM_END_PRINTING消息,使对话框可以完成打印的初始化和释放操作。在执⾏⼀个打印任务时,将打印的流程交给CView来进⾏,⽽这个CView是虚拟的,只是⽤来完成打印⼀些操作,其它内容则完全不负责处理,⽽当要执⾏CView::OnPrint时,则⼜将处理的具体内容传回到对话框,⽽对话框则只需要响应WM_MY_PRINT消息即可:
pFrame->m_pCallerDlg->SendMessage(WM_MY_PRINT,(WPARAM) pDC, (LPARAM) pInfo);
使打印的具体处理⼜传回到对话框中,使开发⼈员根据具体的需要写WM_MY_PRINT的处理函数就可
以实现打印,⽽
深入浅出mfc
CView::OnPrint(CDC* pDC, CPrintInfo* pInfo)的参数也从WM_MY_PRINT的消息参数传出来,在⽤户的对话框程序中,需要写的代码就很少,主要有以下⼏个步骤,
  建⽴⼀个CPrintFrame的对象,设该对象的指针为pFrame,并将对话框的指针传给该对象的m_pCallerDlg,即pFrame-
>m_pCallerDlg = this;
  调⽤对象的Create函数创建框架窗⼝;例如pFrame->Create(NULL,"频谱打印",WS_OVERLAPPEDWINDOW,CRect(0,0,0,0));
  如果要执⾏打印,则调⽤pFrame->m_pView->OnMyPrint();
  如果要执⾏打印预览,则调⽤:
pFrame->m_pView->OnMyPrintPreview();
例如:
void CDlgPrintDlg::OnPrint() //执⾏打印功能{
 CPrintFrame *pFrame = new CPrintFrame;
 pFrame->m_pCallerDlg = this;
 pFrame->Create(NULL,"Curve Print",WS_OVERLAPPEDWINDOW,CRect(0,0,0,0));
 pFrame->m_pView->OnMyPrint();
}
void CDlgPrintDlg::OnPrintPreview() //执⾏打印预览功能{
 CPrintFrame *pFrame = new CPrintFrame;
 pFrame->m_pCallerDlg = this;
 pFrame->Create(NULL,"Curve Print
 Preview",WS_OVERLAPPEDWINDOW,CRect(0,0,0,0));
 pFrame->m_pView->OnMyPrintPreview();
}
 在对话框中响应 WM_BEGIN_PRINTING, WM_END_PRINTING,WM_MY_PRINT消息,分别完成打印的初始化,释放和具体的打印操作;如在⽰例程序中添加了三个消息响应函数来执⾏该功能。
ON_MESSAGE(WM_BEGIN_PRINTING,OnBeginPrinting)
ON_MESSAGE(WM_END_PRINTING,OnEndPrinting)
ON_MESSAGE(WM_MY_PRINT,OnMyPrint)
 其中OnMyPrint是跟具体要打印什么内容有关的开发⼈员要重点完成的代码,可以打印表格,图⽚,数据,只要GDI绘图可以进⾏的操作在这⾥都可以完成。由于打印预览的⼀部分⼯作在CView类⾥完成,因此在⽤户程序中只需要相应WM_MY_PRINT消息就可以执⾏打印预览的功能,⽽不需要另外编写打印预览代码。
  本⽂提供的CPrintFrame和CPrintView类是连个可重⽤的类,开发者只需要把这两个类对应的四个⽂件拷贝到⼯程⽂件所在⽬录中(PrintFrame.h, PringtView.h,PrintFrame.cpp, PrintView.cpp),并将这四个⽂件加⼊⼯程,并在需要执⾏打印功能的代码处加⼊
#include "PrintFrame.h"
#include "PrintView.h"
  然后按照上述5个步骤进⾏即可以实现⼀个功能完整的打印程序,利⽤上述类实现对话框打印不但节省开发者许多时间,⽽且功能很强⼤,能达到很专业的⽔平,但是该⽅法有⼀个缺点,笔者发现如果开发者使⽤静态连接的MFC库时则会出错,只适⽤于Use MFC in a Shelled DLL情况,⽽且必须使程序为Debug版本的。
 3、⽰例代码的执⾏效果
图1 执⾏打印功能的对话框
  当按下打印预览后则会产⽣⼀个框架窗⼝,显⽰打印预览的内容,如图2所⽰:
图2 打印预览效果图
  可以在上图的界⾯上按两页同时对两页预览,如图3所⽰:
图3 两页同时预览效果图
但有⼀点需要注意,在预览界⾯上的打印按钮不可⽤,如果按该"打印"钮则直接等于将预览窗⼝关掉,因此要执⾏打印功能必须另外在对话框的界⾯上放⼀个打印按钮,如果执⾏了"打印"功能,则会弹出⼀个选择打印机的对话框,如图4所⽰。这个对话框是MFC的打印结构内置的,不可以消除,当⽤户选择了正确的打印机后则可以打印出具体的内容了。
图4 打印机选择对话框
 4、 结束语
  本⽂从分析MFC的原代码⼊⼿,利⽤MFC的CView类提供的打印和打印预览功能进⾏了在对话框中的打印和打印预览。利⽤⾯向对象的C++写了两个可重⽤类CPrintFrame和CPrintView,实现在对话框中的打印和打印预览功能,极⼤的简化了对话框打印程序的编写。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。