按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
CMyView::OnPreparePrinting 。这个函数接受一个CPrintInfo 指针做为参数,允许
使用者设定Document 的打印长度(从第几页到第几页)。预设页码是1 至
0xFFFF , 程序员应该在OnPreparePrinting 中调用SetMaxPage 预设页数。
SetMaxPage 之后,程序应该调用CView::DoPreparePrinting ,它会显示【打印】
对话框,并产生一个打印机DC 。当对话框结束,CPrintInfo 也从中获得了使用
者设定的各个打印项目(例如从第n1 页印到第n2 页) 。
Framework 如何得知使用者对于打印状态的设定?CPrintInfo 有五个函数可用,下一
节有更详细的说明。
■针对每一页,Framework 会调用CMyView::OnPrepareDC,这函数在前一章介绍
CScrollView 时也曾提过,当时是因为我们使用卷动窗口,而由于卷动的关系,
绘图之前必须先设定DC 的映射模式和原点等性质。这次稍有不同的是,它收
到打印机DC 做为第一参数,CPrintInfo 对象做为第二参数。我们改写这个函
式,使它依目前的页码来调整DC ,例如改变打印原点和截割区域以保证印出
来的Document 内容的合适性等等。
■稍早我一再强调所有绘图动作都应该集中在OnDraw 函数中,Framework 会自
动调用它。更精确地说,Framework 其实是先调用OnPrint,传两个参数进去,
第一参数是个DC , 第二参数是个CPrintInfo 指针。OnPrint 内部再调用
OnDraw,这次只传DC 过去,做为唯一参数:
// in VIEWCORE。CPP
void CView::OnPrint(CDC* pDC; CPrintInfo*)
{
ASSERT_VALID(pDC);
// Override and set printing variables based on page number
OnDraw(pDC); // Call Draw
}
683
…………………………………………………………Page 746……………………………………………………………
第篇 深入 MFC 程式設計
有了这样的差异,我们可以这么区分这两个函数的功能:
z OnPrint:负责「只在打印时才做(屏幕显示时不做)」的动作。例如印出
表头和页尾。
z OnDraw :共通性绘图动作(包括输出到屏幕或打印机上)都在此完成。
看看另一个函数OnPaint:
// in VIEWCORE。CPP
void CView::OnPaint()
{
// standard paint routine
CPaintDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc);
}
你会发现原来它们是这么分工的:
WM_MAND
CView::OnPrint 唯「打印」才有之工作,将在此进行
(ID_FILE_PRI NT) CView::OnPrint
CView::OnDraw 「打印」与「显示」共通的
CView::OnDraw
工作,在此进行
WM_ PA INT CView ::OnPaint 唯「显示」才有的工作,将在此进行
CView::OnPaint
所谓「显示」是指输出到屏幕上,「打印」是指输出到打印机上。
由同一函数完成显示(display )与打印(print )动作,才能够达到「所见即所得」(What
You See Is What You Get ,WYSIWYG )的目的。如果你不需要一个WYSIWYG 程序,
可以改写OnPrint 使它不要调用OnDraw,而调用另一个绘图例程。
不要认为什么情况下都需要WYSIWYG 。一个文字编辑器可能使用粗体字打印但使用控
制码在屏幕上代表这粗体字。
684
…………………………………………………………Page 747……………………………………………………………
第 12 章 列印與預樱А�
Scribble 打印机制的增强
MFC 预设的打印机制够聪敏了,但还没有聪敏到解决所有的问题。这些问题包括:
■打印出来的影像可能不是你要的大小
■不会分页
■没有表头(header )
■没有页尾(footer )
毕竟屏幕输出和打印机输出到底还是有着重大的差异。窗口有卷动杆而打印机没有,这
伴随而来的就是必须计算Document 的大小和纸张的大小,以解决分页的问题;此外,
我们必须想想,在MFC 预设的打印机制中,改写哪一个地方,才能让我们有办法在
Document 的输出页加上表头或页尾。
打印机的页和文件的页
首先,我们必须区分「页」对于Document 和对于打印机的不同意义。从打印机观点来
看,一页就是一张纸,然而一张纸并不一定容纳Document 的一页。例如你想印一些通
讯资料,这些资料可能是要被折叠起来的,因此一张纸印的是Document 的第一页和最
后一页(亲爱的朋友,想想你每天看的报纸)。又例如印一个巨大的电子表格,它可能是
Document 上的一页,却占据两张A4 纸。
MFC 这个Application Framework 把关于打印的大部份信息都记录在CPrintInfo 中,其
中数笔资料与分页有密切关系。下表是取得分页资料的相关成员,其中只有SetMaxPage
和m_nCurPage 和m_nNumPreviewPages 在Scribble 程序中会用到,原因是Scribble
程序对许多问题做了简化。
685
…………………………………………………………Page 748……………………………………………………………
第篇 深入 MFC 程式設計
CPrintInfo 成员名称 参考到的打印页
GetMinPage/SetMinPage Document 中的第一页
GetMaxPage/SetMaxPage Document 中的最后一页
GetFromPage 将被印出的第一页(出现在【打印】对话框,图12…1b)
GetToPage 将被印出的最后一页(出现在【打印】对话框)
m_nCurPage 目前正被印出的一页(出现在【打印状态】对话框)
m_nNumPreviewPages 预览窗口中的页数(稍后将讨论之)
注:页码从1 (而不是0 )开始。
CPrintInfo 结构中记录的「页」数,指的是打印机的页数;Framework 针对每一「页」
调用OnPrepareDC 以及OnPrint 时,所指的「页」也是打印机的页。当你改写
OnPreparePrinting 时指定Document 的长度,所用的单位也是打印机的「页」。如果
Document 的一页恰等于打印机的一页(一张纸),事情就单纯了;如果不是,你必须在
两者之间做转换。
Scribble Step5 设定让每一份Document 使用打印机的两页。第一页只是单纯印出文件名
称(文件名称),第二页才是文件内容。假设我利用View 窗口卷动杆在整个Document
四周画一四方圈的话,我希望这一四方圈落入第二页(第二张纸)中。当然,边界留白
必须考虑在内,如图12…6。除此之外,我希望第二页(文件内容)最顶端留一点空间,
做为表头。本例在表头中放的是文件名称。
686
…………………………………………………………Page 749……………………………………………………………
第 12 章 列印與預樱А�
图12…6 Scribble Step5 的每一份文件打印时有两页,第一页是文件名称,
第二页是文件内容, 最顶端留有一个表头。
配置GDI 绘图工具
绘图难免需要各式各样的笔、刷、颜色、字形、工具。这些GDI 资源都会占用内存,
而且是GDI 模块的heap 。虽说Windows 95 对于USER 模块和GDI 模块的heap 已
有大幅改善,使用32 位heap ,不再局限64KB,但我们当然仍然不希望看到浪费的情
况发生,因此最好的方式就是在打印之前配置这些GDI 绘图对象,并在打印后立刻释放。
看看图12…5,配置GDI 对象的最理想时机显然是OnBeginPrinting,两个理由:
1。 每当Framework 开始一份新的打印工作,它就会调用此函数一次,因此不同
打印工作所需的不同工具可在此有个替换。
2。 此函数的参数是一个和「打印机DC 」有附着关系的CDC 对象指针,我们直接
从此一CDC 对象中配置绘图工具即可。
687
…………………………………………………………Page 750……………………………………………………………
第篇 深入 MFC 程式設計
配置得来的GDI 对象可以储存在View 的成员变量中,供整个打印过程使用。使用时
机当然是OnPrint。如果你必须对不同的打印页使用不同的GDI 对象,CPrintInfo 中的
m_nCurPage 可以帮你做出正确的决定。