注释
自联机文档中首次包含此说明以来,尚未更新以下技术说明。 因此,某些过程和主题可能过期或不正确。 有关最新信息,建议在在线文档索引中搜索您感兴趣的主题。
此说明介绍了自定义打印和打印预览的过程,并描述了所使用的 CView
回调例程以及回调例程和成员函数的目的 CPreviewView
。
问题
MFC 为大多数打印和打印预览需求提供了完整的解决方案。 在大多数情况下,只需要其他代码才能打印和预览视图。 但是,有一些方法可以优化打印,这些打印需要开发人员付出大量精力,某些应用程序需要向打印预览模式添加特定的用户界面元素。
高效打印
当 MFC 应用程序使用标准方法打印时,Windows 会将所有图形设备接口(GDI)输出调用定向到内存中图元文件。 调用时 EndPage
,Windows 对打印机需要打印一页的每个物理带播放一次图元文件。 在此呈现过程中,GDI 经常查询中止过程以确定它是否应继续。 通常,中止过程允许处理消息,以便用户可以使用打印对话框中止打印作业。
遗憾的是,这会减缓打印过程。 如果应用程序中的打印速度必须快于使用标准技术实现,则必须实现手动带带。
打印带状
若要手动带带,必须重新实现打印循环, OnPrint
以便每页多次调用(每条带一次)。 打印循环在函数中 OnFilePrint
实现,viewprnt.cpp。
CView
在 -derived 类中,将重载此函数,以便处理打印命令的消息映射条目调用打印函数。
OnFilePrint
复制例程并更改打印循环以实现带状。 你可能还需要将带状矩形传递到打印函数,以便可以根据打印的页面部分优化绘图。
其次,在绘制带子时必须经常调用 QueryAbort
。 否则,中止过程将不会被调用,用户将无法取消打印作业。
打印预览:带有用户界面的电子纸张
从本质上讲,打印预览会尝试将显示器转换为打印机的仿真。 默认情况下,主窗口的工作区用于在窗口中完全显示一两页。 用户可以放大页面的某个区域,以便更详细地查看它。 借助其他支持,用户甚至可能允许在预览模式下编辑文档。
自定义打印预览
此说明仅处理修改打印预览的一个方面:将 UI 添加到预览模式。 可以进行其他修改,但此类更改未达到此讨论范围。
将 UI 添加到预览模式
从
CPreviewView
. 派生视图类为所需的 UI 方面添加命令处理程序。
如果要向显示添加视觉方面,请在调用
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”。