《关于windows编程技术11GDI编程4图元文件与打印.doc》由会员分享,可在线阅读,更多相关《关于windows编程技术11GDI编程4图元文件与打印.doc(30页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第11章 GDI编程4图元文件与打印图元文件是一种矢量图形文件,用于绘图指令序列的文件存储和播放再现。与点阵图像相比,图形文件所占的空间小,且可任意缩放而不产生马赛克效应, 但是绘制图形需要一定的时间。图元文件还可用于交互绘图中的图形重绘和图形软件中的图元编辑。GDI除了支持图形的屏幕绘制外,也支持图形的打印输出。使用传统的API进行Windows的打印编程,异常复杂和艰难。而MFC对打印功能的封装,大大简化了程序员的打印编程工作。本章将对使用MFC进行图元文件和打印编程的具体方法分别做一些简单介绍。11.1 图元文件GDI从一开始就支持(图)元文件(metafile),早期(1985年起)的
2、版本为WMF(Windows MetaFile,视窗元文件),主要针对Win16(Win3.x),后来(1990年起)也支持Win32(Win95/ 98/Me)。以后(1993年)随Windows NT推出了改进的图元文件版本EMF(Enhanced Windows MetaFile,增强型视窗元文件),只支持Win32(Win95/98/Me/NT/2000/XP/Vista/7)。现在(2001年起)又随Windows XP和GDI+推出了加强型图元文件EMFEMF+,可以同时支持GDI和GDI+。表11-1 图元文件所支持的GDI类型元文件类型Win16 GDIWin32 GDIWin
3、32/64 GDI+WMFEMFEMF+本节只介绍GDI中的图元文件格式WMF和EMF,重点介绍在MFC中使用图元文件。至于GDI+中的图元文件格式EMF+和如何在GDI+编程中使用图元文件及其相关类,将在14.4节中介绍。11.1.1 图元文件格式下面分别介绍WMF和EMF的具体文件格式。1WMF文件格式l 元文件结构WMF文件由文件头和若干元文件记录组成,参见图11-1。视窗元文件头元文件记录图11-1 WMF的文件结构l 元文件头WMF的文件头用结构METAHEADER定义:typedef struct tagMETAHEADER WORD mtType; / 元文件类型:内存=0、磁盘
4、文件=1 WORD mtHeaderSize; / 文件头大小的字数 WORD mtVersion; / 系统的版本号:支持DIB=0x0300、不支持DIB=0x0100 DWORD mtSize; / 文件大小的字数 WORD mtNoObjects; / 同时存在于元文件内的最大对象数 DWORD mtMaxRecord; / 元文件中最大记录的字大小 WORD mtNoParameters; / 保留字段 METAHEADER;l 元文件记录WMF的元文件记录用结构METARECORD定义:typedef struct tagMETARECORD DWORD rdSize; / 记录大
5、小的字数 WORD rdFunction; / 功能/函数号(记录类型META_XXX) WORD rdParm1; / 函数参数数组,逆序排列 METARECORD;WMF中的图元文件记录类型共有67种,包含所有的绘图设置和操作(DC函数),例如:设置二元光栅操作(符号常量META_SETROP2,对应数值0x0104)、绘制矩形(META_RECTANGLE,0x041B)和输出文本(META_TEXTOUT,0x0521)等。2EMF文件格式l 元文件结构EMF文件由文件头、可选的描述串和调色板、及若干元文件记录组成,参见图11-2。增强型元文件头描述串调色板元文件记录图11-2 EMF
6、的文件结构l 元文件头EMF的文件头用结构ENHMETAHEADER定义(比WMF的复杂得多):typedef struct tagENHMETAHEADER DWORD iType; / 记录类型,必须 = EMR_HEADER(= 1) DWORD nSize; / 结构的字节大小,可能 sizeof(ENHMETAHEADER) RECTL rclBounds; / 边界矩形(设备单位,含右边和底边) RECTL rclFrame; / 边界矩形(0.01毫米单位HIMETRIC,含右边和底边) DWORD dSignature; / 签名,必须 = ENHMETA_SIGNATURE(
7、= 0x464D4520) DWORD nVersion; / 元文件版本,当前 = 0x10000 DWORD nBytes; / 元文件的字节大小 DWORD nRecords; / 元文件中的记录数 WORD nHandles; / 元文件句柄表中的句柄数(第0个句柄被保留) WORD sReserved; / 保留,必须 = 0 DWORD nDescription; / 描述字符数组中的字符数,无描述串时必须设为0 DWORD offDescription; / 描述串相对于文件头开始处的偏移量,无描述串时必须设为0 DWORD nPalEntries; / 元文件内调色板中的表项数
8、 SIZEL szlDevice; / 以像素为单位的参考设备分辨率 SIZEL szlMillimeters; / 以毫米为单位的参考设备分辨率#if (WINVER = 0x0400) / Win95/WinNT4.0以上 DWORD cbPixelFormat; / 像素格式,无像素格式设置时 = 0、/ 开始设置为DC时 = size0f(PIXELFORMATDESCRIPTOR)、/ 有多个单像素格式设置时 = 指向最后一个像素格式头的指针 DWORD offPixelFormat; / 像素格式的偏移量 DWORD bOpenGL; / 元文件中是否包含OpenGL记录#endi
9、f /* WINVER = 0x0400 */#if (WINVER = 0x0500) / Win98/Win2000以上 SIZEL szlMicrometers; / 以微米表示的参考设备大小#endif /* WINVER = 0x0500 */ ENHMETAHEADER; 其中:typedef struct _RECTL LONG left; LONG top; LONG right; LONG bottom; RECTL;typedef struct tagSIZE LONG cx; LONG cy; SIZE; typedef SIZE SIZEL;l 元文件记录EMF的元文件
10、记录用结构ENHMETARECORD定义(与WMF的METARECORD类似,只是交换了大小和类型的顺序):typedef struct tagENHMETARECORD DWORD iType; / 记录类型(功能/函数号EMR_XXX) DWORD nSize; / 记录的字节大小 DWORD dParm1; / 传递给GDI函数的参数数组 ENHMETARECORD; EMF中的图元文件记录类型共有121种(几乎是WMF的两倍),包含Win32 GDI的所有绘图设置和操作,还包含若干兼容16位GDI的DC函数。例如:设置二元光栅操作(符号常量EMR_SETROP2,对应数值20)、绘制矩
11、形(EMR_RECTANGLE,43)、输出文本(EMR_ EXTTEXTOUTW,84)和绘制多边形(EMR_POLYPOLYGON /EMR_POLYPOLYGON16,8/91)等。11.1.2 图元文件的MFC编程可以直接利用Windows SDK中的有关API函数进行图元文件编程,但是限于篇幅,这里只介绍如何利用MFC的CMetaFileDC类进行图元文件的编程。CMetaFileDC是CDC的派生类,是对图元文件功能的封装。CMetaFileDC类很简单,只有一个默认构造函数CMetaFileDC、两个具体创建函数Create(创建WMF)和CreateEnhanced(创建EMF
12、)、两个关闭函数Close(关闭WMF)和CloseEnhanced(关闭EMF),其他主要是使用其父类CDC的成员函数。1创建CMetaFileDC对象创建CMetaFileDC对象分两步进行,首先调用CMetaFileDC类的唯一(默认)构造函数来构造一个空对象,然后再调用该类的Create成员函数来创建一个WMF图元文件对象、或调用CreateEnhanced成员函数来创建一个EMF图元文件对象。下面是这些函数的原型:CMetaFileDC( );BOOL Create(LPCTSTR lpszFilename = NULL);BOOL CreateEnhanced(CDC* pDCRe
13、f, LPCTSTR lpszFileName, LPCRECT lpBounds, LPCTSTR lpszDescription);其中:l pDCRef参考DC,一般取为当前视图类的指针。为NULL时,使用当前显示设备作为参考DC。l lpszFilename图元文件名串的指针,如果为NULL,则创建内存图元文件。l lpBounds边界矩形(单位是0.01毫米),可以是RECT结构或CRect对象的指针。为NULL时,取包含用户图形的最小矩形。l lpszDescription描述字符串,一般包含应用程序名和图名,也可以为NULL。例如:CMetaFileDC metaDC; / 构造
14、元文件DC空对象/ metaDC.Create(NULL); / 创建内存WMF元文件DC/ metaDC.Create(Ltest.wmf); / 创建WMF元文件DC/ 创建内存EMF元文件DC/ metaDC.CreateEnhanced(NULL, NULL, NULL, NULL);/ 获取屏幕大小HDC hdcRef = GetDC()-m_hDC; int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE); / 屏幕宽(毫米)int iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE); / 屏幕高(毫米)in
15、t iWidthPels = GetDeviceCaps(hdcRef, HORZRES); / 屏幕宽(像素)int iHeightPels = GetDeviceCaps(hdcRef, VERTRES); / 屏幕高(像素)/ 获取客户区大小,并将像素坐标转换为0.01毫米坐标RECT rect;GetClientRect(&rect); / 像素坐标rect.right = (rect.right * iWidthMM * 100)/iWidthPels; rect.bottom = (rect.bottom * iHeightMM * 100)/iHeightPels; metaDC
16、.CreateEnhanced(GetDC(), Ltest.emf, &rect, LMFCDraw MixGraphics); / 创建EMF元文件DC2添加绘图记录因为CMetaFileDC是CDC的派生类,可以像用普通CDC对象一样地,使用CMetaFileDC来设置绘图环境和执行绘图指令。例如:metaDC.SelectObject(pLinePen);metaDC.MoveTo(point1); metaDC.LineTo(point2); 3播放图元文件播放图元文件是指通过重画图元文件中的所有绘图记录(执行对应的绘图函数指令)来再现整个图形。可以用CMetaFileDC和CDC类
17、的相关成员函数来播放本程序所创建的图元文件,但是需要用Windows SDK的相关图元函数才能装入和播放磁盘上的图元文件,还可以用CImage类来装入和显示磁盘上的图元文件。1)播放本程序所创建的图元文件为了播放在程序中创建的图元文件,必须先关闭图元文件DC,这可交由CMetaFileDC类的成员函数Close或CloseEnhanced来完成,然后用它们的返回值(图元文件的句柄)来调用CDC类的成员函数PlayMetaFile来播放图元文件。这些函数的原型如下:HMETAFILE Close( ); / 关闭WMF图元文件DC,出错返回NULLHENHMETAFILE CloseEnhanc
18、ed( ); / 关闭EMF图元文件DC,出错返回NULLBOOL PlayMetaFile(HMETAFILE hMF); / 播放WMF图元文件/ 播放EMF图元文件BOOL PlayMetaFile(HENHMETAFILE hEnhMetaFile, LPCRECT lpBounds);由于CDC类的两个PlayMetaFile函数不太听话,可能需要使用下面的SDK函数来代替:BOOL PlayMetaFile(HDC hdc, HMETAFILE hmf); / 播放WMF图元文件BOOL PlayEnhMetaFile( / 播放EMF图元文件 HDC hdc,/ DC句柄 HEN
19、HMETAFILE hemf,/ 增强型图元文件的句柄 CONST RECT *lpRect/ 边界矩形(逻辑单位));其中,lpBounds为边界矩形,逻辑单位(默认为像素)。在使用完图元文件句柄后,应该调用SDK函数:BOOL DeleteMetaFile(HMETAFILE hmf);来删除它(对磁盘元文件它只删除句柄,对内存元文件它会删除内存中元文件的所有内容)。例如:HENHMETAFILE hemf = metaDC.CloseEnhanced();/ pDC-PlayMetaFile(hemf, &rectPixel); / 此函数不听话PlayEnhMetaFile(GetDC
20、()-m_hDC, hemf, &rect1); / SDK函数DeleteEnhMetaFile(hemf);2)装入和播放磁盘上的图元文件MFC所封装的图元文件DC类CMetaFileDC,只是用于创建新图元文件,并添加绘图记录。虽然,可以播放自己创建的图元文件,但是却不能播放已经存在的磁盘图元文件。解决办法有两个:l 使用SDK函数来装入和播放图元文件。可以利用SDK函数GetEnhMetaFile和PlayEnhMetaFile来装入和播放磁盘上的图元文件,这两个函数的原型为:HENHMETAFILE GetEnhMetaFile(LPCTSTR lpszMetaFile); / 装入
21、图元文件BOOL PlayEnhMetaFile( / 显示图元文件 HDC hdc,/ DC句柄 HENHMETAFILE hemf,/ 增强型图元文件的句柄 CONST RECT *lpRect/ 边界矩形(逻辑单位));UINT GetEnhMetaFileHeader( / 获取元文件头/ 缓冲区参数为NULL时返回缓冲区大小,否则返回拷贝到缓冲区中的字节数 HENHMETAFILE hemf,/ 增强型图元文件的句柄 UINT cbBuffer,/ 缓冲区大小 LPENHMETAHEADER lpemh/ 数据缓冲区);例如:HENHMETAFILE hemf = GetEnhMet
22、aFile(Ltest.emf);UINT size = GetEnhMetaFileHeader(hemf, 0, NULL);ENHMETAHEADER *emHeader = (ENHMETAHEADER *)malloc(size);GetEnhMetaFileHeader(hemf, size, emHeader);RECTL rectl = emHeader-rclBounds; / 边界矩形RECT rect = rectl.left, rectl.top, rectl.right, rectl.bottom;PlayEnhMetaFile(GetDC()-m_hDC, hemf
23、, &rect);DeleteEnhMetaFile(hemf); l 使用CImage类来装入和播放图元文件。由于CImage类所支持的图像文件格式中包含了WMF和EMF两种图元文件:n ImageFormatWMFWMF(Windows MetaFile,视窗元文件)。n ImageFormatEMFEMF(Enhanced MetaFile,增强型元文件)。所以可以利用来装入和播放磁盘上的图元文件,例如:CImage img;img.Load(Ltest.emf);img.Draw(pDC-m_hDC, 0, 0);4动态重放图元文件只有在OnDraw函数中绘制的图形才能被自动重绘。而鼠
24、标交互绘图程序中,在左鼠标键松开的响应函数OnLButtonUp中所绘制的图形,并不能被自动重绘。现在我们可以用图元文件来解决这个问题,下面是相关的例子代码,过程参见图11-3。OnDrawOnLButtonUpOnInitialUpdate获取屏幕宽高GetDeviceCaps复制图元记录PlayMetaFile创建内存图元文件CreateEnhanced添加图元记录metaDC定义图元文件对象CMetaFileDC获取DC句柄GetDC()-m_hDC计算矩形宽高rectHimm/rectPixel关闭图元文件CloseEnhanced播放图元文件PlayEnhMetaFile创建新内存图
25、元文件CreateEnhanced删除图元文件句柄DeleteEnhMetaFile定义矩形结构RECT视图类变量图11-3 利用图元文件在视图类中实现自动重绘的主要步骤l 在视图类中定义类变量:RECT rectHimm, rectPixel;CMetaFileDC metaDC;l 在视图类的初始化函数OnInitialUpdate中,创建EMF元文件DC:/ 获取参考HDC与屏幕大小HDC hdcRef = GetDC()-m_hDC; int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE); / 屏幕宽(毫米)int iHeightMM = Get
26、DeviceCaps(hdcRef, VERTSIZE); / 屏幕高(毫米)int iWidthPels = GetDeviceCaps(hdcRef, HORZRES); / 屏幕宽(像素)int iHeightPels = GetDeviceCaps(hdcRef, VERTRES); / 屏幕高(像素)/ 计算屏幕大小的HIMETRIC单位(0.01毫米)值和逻辑单位(像素)值rectHimm.left = 0;rectHimm.top = 0;rectHimm.right = iWidthMM * 100; rectHimm.bottom = iHeightMM * 100;rect
27、Pixel.left = 0;rectPixel.top = 0;rectPixel.right = iWidthPels;rectPixel.bottom = iHeightPels;/ 创建内存EMF文件DC(也可将首个NULL改成文件的路径名串/ 如Ldraw.emf来创建磁盘图元文件)metaDC.CreateEnhanced(GetDC(), NULL, &rectHimm, NULL);l 在视图类的OnLButtonUp等函数中,利用图元文件DC,向图元文件添加各种绘图记录。如:metaDC.SelectObject(pLinePen);metaDC.MoveTo(point1)
28、; metaDC.LineTo(point2); l 在视图类的OnDraw函数中,关闭元文件DC,同时获取元文件句柄,播放元文件。然后再创建新的元文件DC,并将老元文件中现有的记录,通过新的元文件DC的播放,加入到新元文件中,最后删除老元文件的句柄。如:/ 关闭元文件DC,获取句柄HENHMETAFILE hemf = metaDC.CloseEnhanced();/ 播放元文件(SDK函数)PlayEnhMetaFile(GetDC()-m_hDC, hemf, &rectPixel);/ pDC-PlayMetaFile(hemf, &rectPixel); / 此函数不太听话/ 创建新
29、元文件DCmetaDC.CreateEnhanced(GetDC(), NULL, &rectHimm, NULL);/ 将老元文件的纪录加入到新元文件中metaDC.PlayMetaFile(hemf, &rectPixel);DeleteEnhMetaFile(hemf); / 删除元文件句柄(SDK函数)l 可以在视图类的某个消息响应函数中利用SDK函数CopyMetaFile或CopyEnhMetaFile来将内存中的图元文件保存到磁盘文件中。这两个函数的原型为:HMETAFILE CopyMetaFile(HMETAFILE hmfSrc, LPCTSTR lpszFile);HEN
30、HMETAFILE CopyEnhMetaFile(HENHMETAFILE hemfSrc, LPCTSTR lpszFile);例如:/ 关闭元文件,获取句柄HENHMETAFILE hemf = CloseEnhMetaFile(hdcMeta);CopyEnhMetaFile(hemf, Ldraw.emf); / 复制到磁盘文件(SDK函数)DeleteEnhMetaFile(hemf); / 删除元文件句柄(SDK函数)l 最后,在视图类的析构函数中,关闭图元文件DC并删除图元文件句柄。例如:HENHMETAFILE hemf = metaDC.CloseEnhanced( );
31、DeleteEnhMetaFile(hemf);5播放图元文件中的记录CMetaFileDC类和其父类CDC中都没有播放图元文件记录的成员函数,但是可以利用CMetaFileDC类的Close或CloseEnhanced成员函数所获得的图元文件句柄,再调用SDK的有关函数PlayEnhMetaFileRecord、EnumEnhMetaFile和EnhMetaFileProc等来绘制图元文件中的指定记录。这些函数的原型为: BOOL PlayEnhMetaFileRecord( / 显示元文件中的记录 HDC hdc,/ DC句柄 LPHANDLETABLE lpHandletable,/ 元
32、文件句柄表 CONST ENHMETARECORD *lpEnhMetaRecord, / 元文件记录 UINT nHandles/ 句柄计数);BOOL EnumEnhMetaFile( / 枚举图元文件/ 遍历图元文件,将每个记录交给回调函数处理 HDC hdc,/ DC句柄 HENHMETAFILE hemf,/ 元文件句柄 ENHMFENUMPROC lpEnhMetaFunc,/ 回调函数 LPVOID lpData,/ 回调函数数据 CONST RECT *lpRect/ 边界矩形(逻辑单位));int CALLBACK EnhMetaFileProc( / 元文件处理函数/ 用户
33、自己定义,由EnumEnhMetaFile函数回调/ 返回FALSE(0)时终止遍历,返回TRUE(非0)时继续遍历 HDC hDC,/ DC句柄 HANDLETABLE *lpHTable,/ 元文件句柄表 CONST ENHMETARECORD *lpEMFR,/ 元文件记录 int nObj,/ 对象计数 LPARAM lpData/ 可选数据);例如(显示指定记录):l 创建EMF文件DCCMetaFileDC metaDC;metaDC.CreateEnhanced(GetDC(), Ltest.emf, &rectHimm, NULL);l 绘制图形(参见图11-4)CPen re
34、dPen(PS_SOLID, 0, RGB(255, 0, 0);metaDC.SelectObject(&redPen);metaDC.Ellipse(10, 10, 150, 100);metaDC.Rectangle(160, 100, 360, 200);l 播放图元文件HENHMETAFILE hemf = metaDC.CloseEnhanced();/ 关闭图元文件/ 播放图元文件PlayEnhMetaFile(GetDC()-m_hDC, hemf, &rectPixel);DeleteEnhMetaFile(hemf); / 删除(关闭)图元文件图11-4 播放图元文件tes
35、t.emfl 自定义回调函数(用于处理图元文件中的每个记录)int CALLBACK EnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, CONST ENHMETARECORD *lpEMFR, int nObj,LPARAM lpData) /*if (lpEMFR-iType = EMR_CREATEPEN / 创建和选入红色笔 | lpEMFR-iType = EMR_SELECTOBJECT) PlayEnhMetaFileRecord(hDC, lpHTable, lpEMFR, nObj);*/if (lpEMFR-iType = EMR
36、_RECTANGLE) / 画矩形PlayEnhMetaFileRecord(hDC, lpHTable, lpEMFR, nObj);return FALSE; / 终止遍历 return TRUE; / 继续遍历l 装入图元文件,枚举(显示)图元文件(中的记录)EnumEnhMetaFile(GetDC()-m_hDC, hemf, / 遍历元文件中的每个记录ENHMFENUMPROC(&EnhMetaFileProc), / 调用回调函数处理NULL, &rectPixel);DeleteEnhMetaFile(hemf); / 删除图元文件输出结果如图11-5。 不绘制椭圆而且不创建和
37、选入红色笔图11-5 显示图元文件test.emf中的记录11.2 打印和打印预览MFC通过CView类同时支持显示和打印功能,可以使用CView类提供的一系列打印与打印预览函数来完成一个打印过程。所谓打印预览(print preview)就是在屏幕上模拟打印机的输出。为了实现文档(包括文本和图形)的打印输出和打印预览,必须(默认已)在自己的派生类中覆盖CView类的成员函数OnDraw。该函数不仅负责屏幕输出,而且也负责向包括打印机在内的其他输出设备的DC输出图形和文本。由于Windows利用DC实现了设备无关的输出,而MFC的CView类封装了显示和打印功能。CView类用一个成员函数On
38、Draw,代替了API原来的负责屏幕输出的函数OnPaint和负责打印输出的函数OnPrint。11.2.1 自动创建在用MFC应用程序向导创建一个MFC应用程序框架时,若在“MFC应用程序向导”对话框的“高级功能”页中,依默认选中“打印和打印预览”复选框,则所建立的程序就具有基本的打印与打印预览功能。图11-6 默认文件菜单中的三个打印菜单项应用程序向导会在文件菜单中自动添加了打印(ID_FILE_PRINT)、打印预览(ID_FILE_PRINT_PREVIEW)和打印设置(ID_FILE_PRINT_SETUP)三个菜单项(参见图11-6),在工具条中自动添加了打印按钮,并在视图类中添加
39、了打印与打印预览的消息响应。l 在代码文件添加了消息映射:BEGIN_MESSAGE_MAP(CDrawView, CView)/ 标准打印命令ON_COMMAND(ID_FILE_PRINT, &CView:OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView:OnFilePrint)ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView:OnFilePrintPreview)END_MESSAGE_MAP()应用程序向导还在视图类中添加准备打印、开始打印和结束打印的消息响应函数(覆盖父类CView的虚函数):l 头
40、文件中添加了函数原型:protected:virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);l 代码文件中添加了函数体:/ CMFView 打印BOOL CMFView:OnPreparePrinting(CPrintInfo* pInfo)/ 默认准备return DoPreparePrinting(pInfo);vo
41、id CMFView:OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)/ TODO: 添加额外的打印前进行的初始化过程void CMFView:OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)/ TODO: 添加打印后进行的清理过程11.2.2 视图打印MFC的打印支持函数大多数包含在CView类中,使文档-视图应用程序具有默认的打印特性。如果要打印多页文档、或想在页面上打印页眉与页脚,则必须覆盖默认的打印函数。表11-2列出了用于打印的若干重要CView类成员函数,这些函数的相互关系和
42、调用顺序参见图11-7。表11-2 用于打印的重要CView类成员函数成员函数说明OnPreparePrinting在用户要求打印或预览文档时,由应用程序框架调用。在该函数中调用DoPreparePrinting函数。可修改传给DoPreparePrinting函数的CPrintInfo对象,以改变打印对话框的默认设置。DoPreparePrinting由OnPreparePrinting调用。显示公用打印对话框,创建打印DC。OnBeginPrinting由应用程序框架在调用OnPreparePrinting之后,开始打印预览作业之前调用。主要用于分配打印专用的GDI资源(如字体等)。调用返
43、回后,开始打印作业,每次打印一页。OnPrepareDC每打印一页,应用程序框架都要依次调用OnPrepareDC和OnPrint函数。OnPrepareDC函数负责对当前页的DC进行必要的修改,也可用于分析CPrintInfo对象的属性(如文档页数)。若没有设定文档长度,则OnPrepareDC假定文档长度为1页,并在打印一页后停止执行打印系列。OnPrint由应用程序框架在调用OnPrepareDC后立即调用。负责打印图形的输出,默认是调用OnDraw。若要打印多页文档、或想在页面上打印页眉与页脚,则需要另外处理。OnEndPrintPreview若为打印预览,则应用程序框架在调用OnEn
44、dPrinting之前调用OnEndPrintPreview。默认的OnEndPrintPreview进行下列操作:撤销预览窗口恢复应用程序的原状态,然后调用OnEndPrinting函数。OnEndPrinting在打印作业或打印预览结束时,由应用程序框架调用。主要用于释放分配给打印DC的GDI资源。视图类在支持打印方面所承担的工作:l 通知应用程序框架文档中有多少页要打印(或接受默认文档长度为1页)l 分配和释放打印所需要的GDI资源l 当要求打印某页时,绘出该部分文档l 需要时,在打印给定页前,输出ESC代码以改变打印机的模式(如改变打印方向)应用程序框架在支持打印方面所承担的工作:l
45、显示打印对话框l 为打印机创建适用的CDC对象l 调用CDC的StartDoc和EndDoc成员函数l 重复调用CDC类的成员函数StartPage,通知视图类哪一页需要打印,然后调用CDC类的成员函数EndPagel 在适当的时候调用 CView类的打印成员函数DoPreparePrinting初始化OnPreparePrintingOnBeginPrintingOnPrepareDC打印文档页OnDrawOnPrintOnEndPrintPreviewOnEndPrinting清理图11-7 打印的三个主要步骤和标准MFC打印系列中调用的CView成员函数11.2.3 CPrintInfo对象CPrintInfo类是一个独立的类,用于保存和维护打印预览作业的信息。一般不需要