TN030:自定义打印和打印预览

注释

自联机文档中首次包含此说明以来,尚未更新以下技术说明。 因此,某些过程和主题可能过期或不正确。 有关最新信息,建议在在线文档索引中搜索您感兴趣的主题。

此说明介绍了自定义打印和打印预览的过程,并描述了所使用的 CView 回调例程以及回调例程和成员函数的目的 CPreviewView

问题

MFC 为大多数打印和打印预览需求提供了完整的解决方案。 在大多数情况下,只需要其他代码才能打印和预览视图。 但是,有一些方法可以优化打印,这些打印需要开发人员付出大量精力,某些应用程序需要向打印预览模式添加特定的用户界面元素。

高效打印

当 MFC 应用程序使用标准方法打印时,Windows 会将所有图形设备接口(GDI)输出调用定向到内存中图元文件。 调用时 EndPage ,Windows 对打印机需要打印一页的每个物理带播放一次图元文件。 在此呈现过程中,GDI 经常查询中止过程以确定它是否应继续。 通常,中止过程允许处理消息,以便用户可以使用打印对话框中止打印作业。

遗憾的是,这会减缓打印过程。 如果应用程序中的打印速度必须快于使用标准技术实现,则必须实现手动带带。

若要手动带带,必须重新实现打印循环, OnPrint 以便每页多次调用(每条带一次)。 打印循环在函数中 OnFilePrint 实现,viewprnt.cpp。 CView在 -derived 类中,将重载此函数,以便处理打印命令的消息映射条目调用打印函数。 OnFilePrint复制例程并更改打印循环以实现带状。 你可能还需要将带状矩形传递到打印函数,以便可以根据打印的页面部分优化绘图。

其次,在绘制带子时必须经常调用 QueryAbort 。 否则,中止过程将不会被调用,用户将无法取消打印作业。

从本质上讲,打印预览会尝试将显示器转换为打印机的仿真。 默认情况下,主窗口的工作区用于在窗口中完全显示一两页。 用户可以放大页面的某个区域,以便更详细地查看它。 借助其他支持,用户甚至可能允许在预览模式下编辑文档。

自定义打印预览

此说明仅处理修改打印预览的一个方面:将 UI 添加到预览模式。 可以进行其他修改,但此类更改未达到此讨论范围。

将 UI 添加到预览模式

  1. CPreviewView. 派生视图类

  2. 为所需的 UI 方面添加命令处理程序。

  3. 如果要向显示添加视觉方面,请在调用CPreviewView::OnDraw后重写OnDraw和执行绘图。

OnFilePrintPreview

这是用于打印预览的命令处理程序。 其默认实现为:

void CView::OnFilePrintPreview()
{
    // In derived classes, implement special window handling here
    // Be sure to Unhook Frame Window close if hooked.

    // must not create this on the frame. Must outlive this function
    CPrintPreviewState* pState = new CPrintPreviewState;

    if (!DoPrintPreview(AFX_IDD_PREVIEW_TOOLBAR, this,
        RUNTIME_CLASS(CPreviewView), pState))
    {
        // In derived classes, reverse special window handling
        // here for Preview failure case

        TRACE0("Error: DoPrintPreview failed");
        AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
        delete pState;  // preview failed to initialize, delete State now
    }
}

DoPrintPreview 将隐藏应用程序的主窗格。 可以通过在 pState-dwStates> 成员中指定控件栏来保留控制条(这是位掩码,各个控件条的位由AFX_CONTROLBAR_MASK(AFX_IDW_MYBAR)定义)。 窗口 pState-nIDMainPane> 是将自动隐藏和重新分配的窗口。 DoPrintPreview 然后,将为标准预览 UI 创建按钮栏。 如果需要特殊窗口处理(例如隐藏或显示其他窗口),应在调用之前 DoPrintPreview 完成。

默认情况下,当打印预览完成时,它会将控件栏返回到其原始状态和主窗格可见。 如果需要特殊处理,则应在重写 EndPrintPreview中完成。 如果 DoPrintPreview 失败,也提供特殊处理。

DoPrintPreview 调用了:

  • 预览工具栏的对话框模板的资源 ID。

  • 指向用于执行打印预览打印的视图的指针。

  • 预览视图类的运行时类。 这将在 DoPrintPreview 中动态创建。

  • CPrintPreviewState 指针。 请注意,不得在帧上创建 CPrintPreviewState 结构(或派生结构(如果应用程序需要保留更多状态)。 DoPrintPreview 是无模式的,此结构必须生存,直到调用 EndPrintPreview。

    注释

    如果打印支持需要单独的视图或视图类,则应将指向该对象的指针作为第二个参数传递。

EndPrintPreview

调用此项以终止打印预览模式。 通常需要移动到上次在打印预览中显示的文档中的页面。 EndPrintPreview 是应用程序执行此作的机会。 pInfo-m_nCurPage> 成员是上次显示的页面(如果显示两个页面最左侧),指针是用户感兴趣的页面上的提示。 由于应用程序视图的结构对框架未知,因此必须提供要移动到所选点的代码。

在调用 CView::EndPrintPreview之前,应执行大多数作。 此调用将反转并删除 pView、pDC 和 pInfo 的效果 DoPrintPreview

// Any further cleanup should be done here.
CView::EndPrintPreview(pDC, pInfo, point, pView);

CWinApp::OnFilePrintSetup

必须为“打印设置”菜单项映射此项。 在大多数情况下,不需要重写实现。

Page Nomenclature

另一个问题是页码编号和顺序。 对于简单的字处理器类型应用程序,这是一个简单的问题。 大多数打印预览系统都假定每个打印页面对应于文档中的一页。

在尝试提供通用解决方案时,需要考虑几个事项。 想象一下 CAD 系统。 用户具有涵盖多个 E 尺寸工作表的绘图。 在 E 大小(或更小、缩放的)绘图器上,页码编号与简单情况一样。 但在激光打印机上,每张打印 16 个 A 大小的页面,打印预览会考虑“页面”是什么

正如介绍性段落所述,打印预览就像打印机一样。 因此,用户将看到所选特定打印机的结果。 由视图决定在每个页面上打印的图像。

结构中的 CPrintInfo 页面说明字符串提供了一种向用户显示页码的方法(如果它可以表示为每页一个数字(如“第 1 页”或“第 1-2 页”中)。 此字符串由默认实现 CPreviewView::OnDisplayPageNumber的 . 如果需要不同的显示,可以重写此虚拟函数以提供“Sheet1、Sections A、B”。

另请参阅

按编号列出的技术说明
按类别列出的技术说明