1.2.3 MFC的打印功能分析

1.2.3 MFC的打印功能分析
 
 1.框架中的打印
 MFC的框架内置了功能强大的打印和打印预览功能。首先,分析MFC应用程序框架打印的内在机制,
 这样将能更有效地使用打印机。
 
 在视图类及其派生类中,通过重载OnDraw(CDC*pDC)函数,利用它提供的pDC(设备上下文)指针,可以在
 屏幕上显示各种图形和数据。CView类的打印是通过OnPrint(CDC *pDC,CPrintInfo*pInfo)这个函数实现
 的,OnPrint()函数对打印的实现就是简单的调用OnDraw(CDC*pDC)这个函数,把打印机的设备上下文
 指针pDC传递给OnDraw(CDC *pDC)函数。可见CView类对输出到屏幕和输出到打印机的处理都是一样的,
 只是换了一个设备上下文而已(输出到屏幕时是通过OnPaint()函数实现的)。
 
 如果重载OnPrint()函数,可以选择根本不调用OnDraw来支持打印逻辑。OnPrint有两个参数,一个是指向
 打印机设备环境的指针,一个是打印信息对象CPrintInfo的指针,该信息包括纸张大小、当前页码和最大
 页码。对每个需要打印的页,应用程序框架都要调用一次OnPrint(),在OnPrintInfo结构中记录着当前页码。
 
 视图类及其派生类在进行显示和打印之前都会调用virtual void OnParepareDC(CDC *pDC,CPrintInfo* pInfo = null)
 这个虚成员函数来准备设备上下文,可以重载这个虚成员函数,进行坐标转换。下面是MFC框架打印的基本流程:
 
    OnPreparePrint---->设置起始和终止页 
       |
    OnBeginPrinting---->创建GDI对象
       |
    OnPrepareDC(每页)---->设置映射模式,并选择检测打印任务的结尾
       |
    OnPrint(每页)----->打印输出
       |
    是否打印完毕
       |
       y
    OnEndPrinting--->删除GDI对象
 
 CDC::GetDeviceCaps 获得指定设备的信息。
 int GetDeviceCaps(int nIndex)const;
 返回值:如果成功,则返回需要的能力值。
 LOGPIXELSX:沿显示宽度方向,每一逻辑单位的像素数。
 LOGPIXELSY:沿显示高度方向,每一逻辑单位的像素数。
 
 
 
 void CPrintProjView::OnDraw(CDC *pDC)
 {
   pDC->TextOut(400,200,_T("Hello word"));
 }
 
 BOOL CPrintProjView::OnPreparePrinting(CPrintInfo*pInfo)
 {
    pInfo->SetMaxPage(2);
    return DoPreparePrinting(pInfo);
 }
 
 void CPrintProjView::OnPrepareDC(CDC *pDC,CPrintInfo *pInfo)
 {
    CView::OnPrepareDC(pDC,pInfo);
    pDC->SetMapMode(MM_ANISOTROPIC); //转换坐标映射方式
    CSize size = CSize(800,560);
    pDC->SetWindowExt(size);//确定窗口的大小
    //得到实际设备每逻辑英寸的像素数量
    int xLogPixelPerInch = pDC->GetDeviceCaps(LOGPIXELSX);
    int yLogPixelPerInch = pDC->GetDeviceCaps(LOGPIXELSY);
   
    //得到设备坐标和逻辑坐标的比例
    long xExt = (long)size.cx * xLogPixelPerInch / 96;
    long yExt = (long)size.cy * yLogPixelPerInch / 96;
    pDC->SetViewportExt((int)xExt,(int)yExt); //设置视口大小
 }
 
 在上面的程序中,首先将坐标映射方式改变为MM_ANISOSTROPIC方式,即各向异性的意思,
 在这种坐标方式下,x轴和y轴的逻辑单位可以进行任意的缩放。改变坐标映射方式后,就要
 确定窗口大小和视口大小,注意窗口大小就是我们在屏幕上所见的尺寸,,而视口大小是实际
 设备,如打印机等,和显示设备每逻辑英寸的像素数量比较所得的比例尺.
 
 通过函数得到显示器和打印机每逻辑英寸的像素数量,然后对视口大小进行相应的缩放,就可以
 使屏幕上的显示和打印机的输出是一致了.
 
 编译、运行程序,使用打印预览功能,会看到在两个视图和预览两个页面中"Hello word"的位置是
 一样的。
 
 下次在看的时候,将这一部分再串一下。注意下面几点。
 1、只有在MM_ANISOTROPIC和MM_ISOTROPIC映射模式下,SetWindowExt和SetViewportExt才起作用。
    MM_ANISOTROPIC和MM_ISOTROPIC的区别是:
    MM_ANISOTROPIC是不锁定纵横比,也就是x和y各向异性,x和y轴的逻辑单位可以任意缩放。
    MM_ISOTROPIC:是锁定纵横比,x和y轴的比值是1:1

   
 2、SetWindowExt()设置窗口的x和y轴范围,也就是窗口的大小
    SetViewportExt()设置视口的x和y轴范围,也就是视口的大小
 
 3、窗口大小是指:我们在屏幕上所见的尺寸
    视口大小是指:实际设备,如打印机等.

   
2、框架之外的打印
   框架实现了对打印的一些底层支持,直接的打印机制是通过函数StartDoc和EndDoc()来实现的。应用程序
   要使用打印机时,它首先使用CreateDC或PrintDlg来获取指向打印机设备环境的一个句柄,这就使得打印机
   设备驱动程序库模块被加载到内存(如果还没有加载到内存的话),并进行初始化。然后,程序调用StartDoc
   函数,通知一个新文档开始了。StartDoc函数是由GDI模块来处理的。GDI模块调用打印机设备驱动程序中的
   control函数告诉打印机准备打印。
  
   打印一个文档的过程以StartDoc调用开始,以EndDoc调用结束。调用StartPage来开始一页,调用EndPage来
   结束该页。

  
   下面这段代码在对话框中实现了对打印的支持。
   /*
   GetPrinterDC 获取设备环境的句柄。
   HDC GetPrinterDC()const;
   返回值:
   如果成功则返回一个打印机设备环境的句柄;否则返回null.
   说明:
   如果CPrintDialog构造函数的参数bPrintSetupOnly是FALSE(表明显示的是Print对话框,则GetPrinterDC返回一个
   打印机设备环境句柄。当你使用完这个设备环境时,你必须调用Windows DeleteDC函数来删除它。)
   */
   /*
   {
     long cbSize,
     CString lpszDocName,
     CString lpszOutput
   } DOCINFO;
   对文档进行定义的一个结构。
   cbSize:结构的大小
   lpszDocName:文档的名字
   lpszOutput:输出文档的名字
   */
   /*
   StartDoc:开始新的打印作业
   CDC::StartDoc
   int StartDoc(LPDOCINFO lpDocInfo);
   返回值:如果出错,例如存储空间不足或指定端口无效,则返回-1否则返回正值。
   参数:
   lpDocInfo: DOCINFO结构的指针。该结构包含了文档文件和输出文件的名字。
  
   说明:
   通知设备的驱动程序开始一个新的打印作业,其后所有的StartPage和EndPage调用处于假
   脱机状态,直到EndDoc调用出现。这确保了长于一页的文档不被其它作业中断。  
   */
   /*
   EndDoc  结束由StartDoc成员函数启动的打印作业。
   CDC::EndDoc
   int EndDoc();
   返回值:
   如果成功,则返回值大于零或等于零,出错则返回值小于零。下面列出了一般的错误
   类型:
   SP_ERROR:一般错误。
   SP_OUTOFDISK:假脱机所需的磁盘空间不足,没有其它可用的磁盘空间。
   SP_OUTOFMEMORY:假脱机所需的内存不足。
   SP_USERABORT: 用户在打印管理中中止作业。
  
   说明:
   中止由StartDoc成员函数调用的打印作业。在成功完成打印作业后应立即调用。
   如果应用遇到打印错误或取消的打印操作,决不可用EndDoc或AbortDoc去中止
   操作,GDI在返回错误值之前自动中止操作。
  
   */
   /*
   StartPage:通知设备的驱动程序开始新页。
   CDC::StartPage
   int StartPage
   说明:
   调用该成员函数使用打印机驱动程序做好准备接收数据。在StartPage和EndPage之间,
   ResetDC成员函数不起作用。
   */
   /*
   EndPage:通知打印机驱动程序打印页结束。
   CDC::EndPage
   int EndPage()
   返回值:如果成功,则返回大于或等于零的值,如果失败则返回如下错误类型:
   SP_ERROR:一般错误
   SP_APPABORT: 作业终止
   SP_USERABORT:用户在打印管理中中止作业。
   SP_OUTOFDISK:假脱机所需的磁盘空间不足。
   SP_OUTOFMEMORY:假脱机所需的内存不足。
  
   说明:
   通知设备已经写完一页。该成员函数通常用在打印机驱动程序开始新的一页。
   */
   /*
   AbortDoc:终止当前打印任务,擦除自上次调用StartDoc成员函数以业写入设备的任何内容。
   CDC::AbortDoc
   int AbortDoc();
   返回值:如果成功,则返回大于或等于零的值,如果出现错误,则为负值。与EndPage和
   EndDoc返回的错误类型值一样。
   说明:
   终止当前打印任务,并擦除自上次StartDoc以后写入设备的任何任务。
   */
  
   /*
   CPrintInfo没有基类。
   CPrintInfo存储有关一次打印或打印预览的信息。每次选择Print或PrintPreview命令,框架
   就会创建一个CPrintInfo对象。并在命令完成时删除此对象。
  
   CPrintInfo包含打印时的一般信息,例如:要打印页的范围,打印机的状态,当前正在打印的页
   这些信息存放在CPintInfo的对象中;此对象还包括在CPrint对话框中输入的值。
  
   在打印期间,一个CPrintInfo对象在框架和视图类之间传递,并且用于两者之间交换信息。例如:
   框架通过对CPrintInfo类的m_nCurPgae成员赋值,来通知视图类要打印文档的哪一页,视图类检索
   此值,并执行指定页的实际打印。
  
   另一个例子就是文档的长度到打印的时候也不知道多少页。视图类每打印一页都要检测是否到了文档的
   末尾。当到达文档的末尾时,视图类将CPrintInfo的m_bContinuePrinting成员设置为FALSE,通知框架
   停止打印循环。
   */
   /*
   Attach:把Windows设备上下文句柄附加在CDC对象上。
   CDC::Attach
   BOOL Attach(HDC hDC);
   返回值:如果成功,返回非零值,否则为0
   参数:
   hDC:Windows设备上下文。
   说明:
   使用这个函数把hDC附加到CDC对象上。
   */
   /*
   Detach:从CDC对象中分离出Windows设备上下文。
   CDC::Detach
   HDC Detach()
   返回值:Windows设备上下文句柄。
   说明:
   调用该函数将m_hDC从CDC对象中分离出来。并将m_hDC与m_bAttribDC设备为NULL。
   */
   void CPrintProj::Print()
   {
    CDC dc;
    CPrintDialog printDlg(FALSE);
       //利用CPrintDialog生成打印机设备环境
    if(printDlg.DoModual() == IDCANCEL) //让用户选择打印纸张等
       return;
    dc.Attach(printDlg.GetPrinterDC());//让Handle连接到dc上.
    dc.m_bPrinting = TRUE;

    CString strTitle;
    strTitle.LoadString(AFX_IDS_APP_TITLE);

    DOCINFO di; //DOCINFO中有相关的打印信息
    ::ZeroMemory(&di,sizeof(DOCINFO));
    di.cbSize = sizeof(DOCINFO);
    di.lpszDocName = strTitle; //设置标题

    BOOL bPrintingOK = dc.StartDoc(&di); //开始打印

    CPrintInfo Info;
    Info.m_rectDraw.SetRect(0,0,dc.GetDeviceCaps(HORZRES),dc.GetDeviceCaps(VERTRES)); //设置范围.

       OnBeginPrinting(&dc,&Info); //调用你自定义的打印功能.
    fo(UINT page = Info.GetMinPage();page < Info.GetMaxPage() && bPrintOK;page++)
    {
     Info.m_nCurPage = page;
     OnPrint(&dc,&Info); //调用你的"Print page"函数
     bPrintOK = dc.EndPage() > 0; //结束页
    }
    OnEndPrinting(&dc,&Info);//结束打印.

    if(bPrintingOK)
     dc.EndDoc();
    else
     dc.AbortDoc();
    dc.Detach();
   }
  
   说明:其实在Windows环境中是设备无关的.只要有了DC,就可以使用各种GDI函数,而不需要理会是在屏幕或是在
   打印机上绘图.

转载于:https://www.cnblogs.com/scud001/archive/2010/04/21/1717563.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值