• 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函数,而不需要理会是在屏幕或是在
       打印机上绘图.

  • 相关阅读:
    C struct的内存对齐
    C++ 继承、函数重载
    C++ 操作符重载
    C中入栈顺序和运算顺序有关系吗?
    Java 关于finally、static
    C++ 类的复制控制
    Linux中vi的使用
    C++ 类的头文件、实现、使用
    (web)个人项目(挖宝网)
    MariaDB使用enum和set
  • 原文地址:https://www.cnblogs.com/scud001/p/1717563.html
Copyright © 2020-2023  润新知