GDI编程4图元文件与打印.doc_第1页
GDI编程4图元文件与打印.doc_第2页
GDI编程4图元文件与打印.doc_第3页
GDI编程4图元文件与打印.doc_第4页
GDI编程4图元文件与打印.doc_第5页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第11章 GDI编程4图元文件与打印*图元文件是一种矢量图形文件,用于存储和重放Windows程序的绘图指令序列。与点阵图像相比,图形文件所占的空间小,且可任意缩放而不产生马赛克效应, 不过绘制图形需要一定的时间。图元文件还可用于交互绘图中的图形重绘和图形软件中的图元编辑。GDI除了支持图形的屏幕绘制外,也支持图形的打印输出。使用传统的API进行Windows的打印编程,异常复杂和艰难。而MFC对打印功能的封装,大大简化了程序员的打印编程工作。本章将对使用MFC进行图元文件和打印编程的具体方法分别做一些简单介绍。11.1 图元文件GDI从一开始就支持(图)元文件(metafile),早期(1985年起)的版本为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+推出了EMF文件的加强版EMF+,可以同时支持GDI和GDI+。参见表11-1。表11-1 图元文件所支持的GDI类型图元文件类型Win16 GDIWin32 GDIWin32/64 GDI+WMFEMFEMF+本节只介绍GDI中的图元文件格式WMF和EMF,重点介绍在MFC中使用图元文件的方法。至于GDI+中的图元文件格式EMF+和如何在GDI+编程中使用图元文件及其相关类,将在13.5节中简单介绍。11.1.1 图元文件格式下面分别介绍WMF和EMF的具体文件格式。1WMF文件格式l 图元文件结构WMF文件由文件头和若干图元文件记录组成,参见图11-1。视窗图元文件头图元文件记录图11-1 WMF的文件结构l 图元文件头WMF的文件头用结构METAHEADER定义:typedef struct tagMETAHEADER WORD mtType; / 图元文件类型:内存=0、磁盘文件=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; / 记录大小的字数 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的文件结构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(= 0x464D4520) DWORD nVersion; / 图元文件版本,当前 = 0x10000 DWORD nBytes; / 图元文件的字节大小 DWORD nRecords; / 图元文件中的记录数 WORD nHandles; / 图元文件句柄表中的句柄数(第0个句柄被保留) WORD sReserved; / 保留,必须 = 0 DWORD nDescription; / 描述字符数组中的字符数,无描述串时必须设为0 DWORD offDescription; / 描述串相对于文件头开始处的偏移量,无描述串时必须设为0 DWORD nPalEntries; / 图元文件内调色板中的表项数 SIZEL szlDevice; / 以像素为单位的参考设备分辨率 SIZEL szlMillimeters; / 以毫米为单位的参考设备分辨率#if (WINVER = 0x0400) / Win95/WinNT 4.0以上 DWORD cbPixelFormat; / 像素格式,无像素格式设置时 = 0、/ 开始设置为DC时 = size0f(PIXELFORMATDESCRIPTOR)、/ 有多个单像素格式设置时 = 指向最后一个像素格式头的指针 DWORD offPixelFormat; / 像素格式的偏移量 DWORD bOpenGL; / 图元文件中是否包含OpenGL记录#endif /* WINVER = 0x0400 */#if (WINVER = 0x0500) / 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的图元文件记录用结构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)、绘制矩形(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)、两个关闭函数Close(关闭WMF)和CloseEnhanced(关闭EMF),其他主要是使用其父类CDC的成员函数。1创建CMetaFileDC对象创建CMetaFileDC对象分两步进行,首先调用CMetaFileDC类的唯一(默认)构造函数来构造一个空对象,然后再调用该类的Create成员函数来创建一个WMF图元文件对象、或调用CreateEnhanced成员函数来创建一个EMF图元文件对象。下面是这些函数的原型:CMetaFileDC( );BOOL Create(LPCTSTR lpszFilename = NULL);BOOL CreateEnhanced(CDC* pDCRef, LPCTSTR lpszFileName, LPCRECT lpBounds, LPCTSTR lpszDescription);其中:l pDCRef参考DC,一般取为当前视图类的指针。为NULL时,使用当前显示设备作为参考DC。l lpszFilename图元文件名串的指针,如果为NULL,则创建内存图元文件。l lpBounds边界矩形(单位是0.01毫米),可以是RECT结构或CRect对象的指针。为NULL时,取包含用户图形的最小矩形。l lpszDescription描述字符串,一般包含应用程序名和图名,也可以为NULL。例如(被注释掉的代码部分,是针对EMF图元文件的,后同):/ 下面的代码可置于视图类头文件的类定义中CMetaFileDC metaDC; / 定义图元文件DC空对象HMETAFILE hwmf; / 定义WMF句柄/HENHMETAFILE hemf; / 定义EMF句柄/RECT rect; / 定义边界矩形CPoint point0; / 定义直线的起点CPen *pLinePen; / 定义画直线的笔的指针/ 下面的代码可置于视图类的构造函数中metaDC.Create(NULL); / 创建WMF内存DC/metaDC.Create(LTest.wmf); / 创建WMF文件DChwmf = NULL; / 置WMF句柄的初值为空/metaDC.CreateEnhanced(NULL, NULL, NULL, NULL); / 创建EMF内存DC/metaDC.CreateEnhanced(GetDC(), LTest.emf, NULL, /LMyDraw Graphics); / 创建EMF文件DC/hemf = NULL; / 置EMF句柄的初值为空pLinePen = new CPen(PS_SOLID, 0, RGB(255, 0, 0); / 创建笔metaDC.SelectObject(pLinePen); / 选入笔2添加绘图记录因为CMetaFileDC是CDC的派生类,可以像用普通CDC对象一样地,使用CMetaFileDC来设置绘图环境和执行绘图指令。例如(可置于视图类的鼠标响应函数OnLButtonUp中):metaDC.MoveTo(point0); / point0可在OnLButtonDown中赋值metaDC.LineTo(point); / point为鼠标的当前位置点3播放图元文件播放(显示)图元文件是指通过重画图元文件中的所有绘图记录(执行对应的绘图函数指令)来再现整个图形。可以用CMetaFileDC和CDC类的相关成员函数来播放本程序所创建的图元文件,但是需要用Windows SDK的相关图元函数才能装入和播放磁盘上的图元文件。还可以用CImage类来装入和显示(播放)磁盘上的图元文件。1)播放本程序所创建的图元文件为了播放在程序中创建的图元文件,必须先关闭图元文件DC,这可交由CMetaFileDC类的成员函数Close或CloseEnhanced来完成,然后用它们的返回值(图元文件的句柄)来调用CDC类的成员函数PlayMetaFile来播放图元文件。这些函数的原型如下:HMETAFILE Close( ); / 关闭WMF图元文件DC,出错返回NULLHENHMETAFILE CloseEnhanced( ); / 关闭EMF图元文件DC,出错返回NULLBOOL PlayMetaFile(HMETAFILE hMF); / 播放WMF图元文件/ 播放EMF图元文件BOOL PlayMetaFile(HENHMETAFILE hEnhMetaFile, LPCRECT lpBounds);其中,lpBounds为边界矩形,逻辑单位(默认为像素),不能为NULL。在使用完图元文件句柄后,还应该调用SDK函数:BOOL DeleteMetaFile(HMETAFILE hmf);BOOL DeleteEnhMetaFile(HENHMETAFILE hemf);来删除它(对磁盘图元文件它只删除句柄,但对内存图元文件它会删除内存中图元文件的所有内容)。为了由EMF句柄来获取其边界矩形,还需要用到获取EMF文件头的SDK函数:UINT GetEnhMetaFileHeader( / 获取图元文件头/ 缓冲区参数为NULL时返回缓冲区大小,否则返回拷贝到缓冲区中的字节数 HENHMETAFILE hemf,/ 增强型图元文件的句柄 UINT cbBuffer,/ 缓冲区大小 LPENHMETAHEADER lpemh/ 数据缓冲区);例如:/ 关闭图元文件,获取其句柄。代码可置于某个表示绘图完成的菜单项或/ 鼠标/键盘消息的响应函数(如OnKeyDown, nChar = C)中-hemf = metaDC.CloseEnhanced(); / 此行代码针对WMF/*hemf = metaDC.CloseEnhanced(); / 以下代码针对EMF/ 获取边界矩形UINT size = GetEnhMetaFileHeader(hemf, 0, NULL); / 获取图元文件头的大小ENHMETAHEADER *emHeader = (ENHMETAHEADER *)malloc(size); / 分配内存GetEnhMetaFileHeader(hemf, size, emHeader); / 获取图元文件的头/ 将图元文件的边界矩形赋值给类矩形rect.left = emHeader-rclBounds.left;rect.top = emHeader-rclBounds.top;rect.right = emHeader-rclBounds.right;rect.bottom = emHeader-rclBounds.bottom;*/ 播放(显示)图元文件,可置于视图类的OnDraw函数中-if (hwmf != NULL) pDC-PlayMetaFile(hwmf); / 针对WMF/if (hemf != NULL) pDC-PlayMetaFile(hemf, &rect); / 针对EMF2)装入和播放磁盘上的图元文件MFC所封装的图元文件DC类CMetaFileDC,只是用于创建新图元文件,并添加绘图记录。虽然,可以播放自己创建的图元文件,但是却不能播放已经存在的磁盘图元文件。解决办法有两个:l 使用SDK中的API函数来装入图元文件可以利用API函数GetMetaFile(已过时)/GetEnhMetaFile来装入和播放磁盘上的WMF/WMF和EMF图元文件:HMETAFILE GetMetaFile(LPCTSTR lpszMetaFile); / 装入WMF图元文件(已过时)HENHMETAFILE GetEnhMetaFile(LPCTSTR lpszMetaFile); / 装入WMF和EMF图元文件再用CDC类的PlayMetaFile来播放。例如:CDC *pDC = GetDC(); / 共用HMETAFILE hwmf = GetMetaFile(Ltest.wmf); / 针对WMFpDC-PlayMetaFile(hwmf);DeleteMetaFile(hwmf);/*HENHMETAFILE hemf = GetEnhMetaFile(Ltest.emf); / 针对EMF / 获取边界矩形的代码(同前)pDC-PlayMetaFile(hemf, &rect);DeleteEnhMetaFile(hemf); */ReleaseDC(pDC); / 共用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函数中绘制的图形才能被自动重绘。而鼠标交互绘图程序中,在左鼠标键松开的响应函数OnLButtonUp中所绘制的图形,并不能被自动重绘。现在我们可以用图元文件来解决这个问题,下面是相关的例子代码,主要过程参见图11-3。OnLButtonUp复制图元记录PlayMetaFile创建内存图元文件CreateEnhanced添加图元记录metaDC定义图元文件对象CMetaFileDC metaDC获取边界矩形GetEnhMetaFileHeader获取图元文件句柄CloseEnhanced播放图元文件PlayEnhMetaFile创建新内存图元文件CreateEnhanced删除旧图元文件DeleteEnhMetaFile视图类类变量视图类构造函数保存图元文件CopyEnhMetaFileOnDraw视图类析构函数OnFileSave图11-3 利用图元文件在视图类中实现自动重绘的主要步骤l 在视图类中定义类变量:CMetaFileDC metaDC; / 定义图元文件DCHENHMETAFILE hemf; / 定义图元文件句柄RECT rect; / 定义边界矩形bool m_bChanged; / 判断是否修改了图形CPoint point0; / 起点CPen *pLinePen; / 画直线的笔 / 其他类变量l 在视图类的构造函数中,创建EMF图元文件DC并初始化类变量:/ 创建内存EMF型图元文件DCmetaDC.CreateEnhanced(NULL, NULL, NULL, NULL); hemf = NULL; / 初始化图元文件句柄为空m_bChanged = false;/ 初始化修改图形的布尔变量为假pLinePen = new CPen(0, 0, RGB(255, 0, 0); / 创建笔 / 其他初始化代码l 在视图类的OnLButtonUp等函数中,利用图元文件DC,向图元文件添加各种绘图记录。如:metaDC.SelectObject(pLinePen); / 选入笔metaDC.MoveTo(point0); / 画直线(从起点到当前点)metaDC.LineTo(point); m_bChanged = true; / 设置修改图形的布尔变量为真l 在视图类的OnDraw函数中,关闭图元文件DC,同时获取图元文件句柄,播放图元文件。然后再创建新的图元文件DC,并将老图元文件中现有的记录,通过新的图元文件DC的播放,加入到新图元文件中,最后删除老图元文件的句柄。如:if (m_bChanged) / 如果图形被修改过了,则更新图元文件句柄m_bChanged = false; / 设置修改图形的布尔变量为假/ 删除旧图元文件句柄if(hemf != NULL) DeleteEnhMetaFile(hemf);hemf = metaDC.CloseEnhanced(); / 获取新图元文件句柄 / 获取边界矩形的代码(同前)/ 创建新图元文件DCmetaDC.CreateEnhanced(pDC, NULL, NULL, NULL);/ 将老图元文件的纪录加入到新图元文件中metaDC.PlayMetaFile(hemf, &rect);/ 播放当前的图元文件(将所画图形显示在窗口客户区)if(hemf != NULL) pDC-PlayMetaFile(hemf, &rect);l 还可以在视图类的某个消息响应函数中利用SDK函数CopyMetaFile或CopyEnhMetaFile来将内存中的图元文件保存到磁盘文件中。这两个函数的原型为:HMETAFILE CopyMetaFile(HMETAFILE hmfSrc, LPCTSTR lpszFile);HENHMETAFILE CopyEnhMetaFile(HENHMETAFILE hemfSrc, LPCTSTR lpszFile);例如:if(hemf != NULL) CopyEnhMetaFile(hemf, Ldraw.emf);l 最后,在视图类的析构函数中,关闭图元文件DC并删除图元文件句柄。例如:if(hemf = NULL) hemf = metaDC.CloseEnhanced(); DeleteEnhMetaFile(hemf);5播放图元文件中的记录CMetaFileDC类和其父类CDC中都没有播放图元文件记录的成员函数,但是可以利用CMetaFileDC类的Close或CloseEnhanced成员函数所获得的图元文件句柄,再调用SDK中的有关API函数PlayEnhMetaFileRecord、EnumEnhMetaFile和EnhMetaFileProc等来绘制图元文件中的指定记录。这些函数的原型为: BOOL PlayEnhMetaFileRecord( / 显示图元文件中的记录 HDC hdc,/ DC句柄 LPHANDLETABLE lpHandletable,/ 图元文件句柄表 CONST ENHMETARECORD *lpEnhMetaRecord, / 图元文件记录 UINT nHandles/ 句柄计数);BOOL EnumEnhMetaFile( / 枚举图元文件/ 遍历图元文件,将每个记录交给回调函数处理 HDC hdc,/ DC句柄 HENHMETAFILE hemf,/ 图元文件句柄 ENHMFENUMPROC lpEnhMetaFunc,/ 回调函数 LPVOID lpData,/ 回调函数数据 CONST RECT *lpRect/ 边界矩形(逻辑单位));int CALLBACK EnhMetaFileProc( / 图元文件处理函数/ 用户自己定义,由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, NULL, NULL);l 绘制图形(参见图11-4)CPen redPen(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, &rect);DeleteEnhMetaFile(hemf); / 删除(关闭)图元文件图11-4 播放图元文件test.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_RECTANGLE) / 画矩形PlayEnhMetaFileRecord(hDC, lpHTable, lpEMFR, nObj);return FALSE; / 终止遍历 return TRUE; / 继续遍历l 装入图元文件,枚举(显示)图元文件(中的记录)EnumEnhMetaFile(GetDC()-m_hDC, hemf, / 遍历图元文件中的每个记录ENHMFENUMPROC(&EnhMetaFileProc), / 调用回调函数处理NULL, &rectPixel);DeleteEnhMetaFile(hemf); / 删除图元文件输出结果如图11-5。 不绘制椭圆而且不创建和选入红色笔图11-5 显示图元文件test.emf中的记录11.2 打印和打印预览MFC通过CView类同时支持显示和打印功能,可以使用CView类提供的一系列打印与打印预览函数来完成一个打印过程。所谓打印预览(print preview)就是在屏幕上模拟打印机的输出。为了实现文档(包括文本和图形)的打印输出和打印预览,必须(默认已)在自己的派生类中覆盖CView类的成员函数OnDraw。该函数不仅负责屏幕输出,而且也负责向包括打印机在内的其他输出设备的DC输出图形和文本。由于Windows利用DC实现了设备无关的输出,而MFC的CView类封装了显示和打印功能。CView类用一个成员函数OnDraw,代替了API原来的负责屏幕输出的函数OnPaint和负责打印输出的函数OnPrint。11.2.1 自动创建在用MFC应用程序向导创建一个MFC应用程序框架时,若在“MFC应用程序向导”对话框的“高级功能”页中,依默认选中“打印和打印预览”复选框,则所建立的程序就具有基本的打印与打印预览功能。应用程序向导会在文件菜单中自动添加了打印(ID_FILE_PRINT)、打印预览(ID_FILE_PRINT_PREVIEW)和打印设置(ID_FILE_PRINT_SETUP)三个菜单项(参见图11-6),在工具条中自动添加了打印按钮,并在视图类中添加了打印与打印预览的消息响应。l 在代码文件添加了消息映射:图11-6 默认文件菜单中的三个打印菜单项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 头文件中添加了函数原型: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);void CMFView:OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)/ TODO: 添加额外的打印前进行的初始化过程void CMFView:OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)/ TODO: 添加打印后进行的清理过程11.2.2 视图打印MFC的打印支持函数大多数包含在CView类中,使文档-视图应用程序具有默认的打印特性。如果要打印多页文档、或想在页面上打印页眉与页脚,则必须覆盖默认的打印函数。表11-2列出了用于打印的若干重要CView类成员函数,这些函数的相互关系和调用顺序参见图11-7。表11-2 用于打印的重要CView类成员函数成员函数说明OnPreparePrinting在用户要求打印或预览文档时,由应用程序框架调用。在该函数中调用DoPreparePrinting函数。可修改传给DoPreparePrinting函数的CPrintInfo对象,以改变打印对话框的默认设置。DoPreparePrinting由OnPreparePrinting调用。显示公用打印对话框,创建打印DC。OnBeginPrinting由应用程序框架在调用OnPreparePrinting之后,开始打印预览作业之前调用。主要用于分配打印专用的GDI资源(如字体等)。调用返回后,开始打印作业,每次打印一页。OnPrepareDC每打印一页,应用程序框架都要依次调用OnPrepareDC和OnPrint函数。OnPrepareDC函数负责对当前页的DC进行必要的修改,也可用于分析CPrintInfo对象的属性(如文档页数)。若没有设定文档长度,则OnPrepareDC假定文档长度为1页,并在打印一页后停止执行打印系列。OnPrint由应用程序框架在调用OnPrepareDC后立即调用。负责打印图形的输出,默认是调用OnDraw。若要打印多页文档、或想在页面上打印页眉与页脚,则需要另外处理。OnEndPrintPreview若为打印预览,则应用程序框架在调用OnEndPrinting之前调用OnEndPrintPreview。默认的OnEndPrintPreview进行下列操作:撤销预览窗口恢复应用程序的原状态,然后调用OnEndPrinting函数。OnEndPrinting在打印作业或打印预览结束时,由应用程序框架调用。主要用于释放分配给打印DC的GDI资源。视图类在支持打印方面所承担的工作:l 通知应用程序框架文档中有多少页要打印(或接受默认文档长度为1页)l 分配和释放打印所需要的GDI资源l 当要求打印某页时,绘出该部分文档l 需要时,在打印给定页前,输出ESC代码以改变打印机的模式(如改变打印方向)应用程序框架在支持打印方面所承担的工作:l 显示打印对话框l 为打印机创建适用的CDC对象l 调用CDC的StartDoc和EndDoc成员函数l 重复调用CDC类的成员函数StartPage,通知视图类哪一页需要打印,然后调用CDC类的成员函数EndPagel 在适当的时候调用 CView类的打印成员函数DoPreparePrinting初始化OnPreparePrintingOnBeginPrintingOnPrepareDC打印文档页OnDrawOnPrintOnEndPrintPreviewOnEndPrinting清理图11-7 打印的三个主要步骤和标准MFC打印系列中调用的CView成员函数11.2.3 CPrintInfo对象CPrintInfo类是一个独立的类,用于保存和维护打印预览作业的信息。一般不需要自己创建CPrintInfo对象,应用程序框架在打印序列开始时,会自动创建一个CPrintInfo对象,并在打印过程中将其用于在应用程序框架与视图类之间交换信息;在打印序列结束时,应用程序框架会自动销毁该对象。可以通过CPrintInfo类的数据成员访问各种打印作业的信息。下面是CPrintInfo类的常用数据成员:l m_pPD指向CPrintDialog对象的指针,可以用它来设置打印对话框的属性l m_bDirect是否为直接打印(不显示打印对话框)l m_bPreview是否为打印预览l m_bContinuePrinting是否应该继续打印循环,可设置为FALSE来通知应用程序框架结束打印文档页的循环l m_nCurPage当前打印页的号码。每打印一页时,应用程序框架会在调用OnPrepareDC和OnPrint函数之后,更新当前打印页码l m_nNumPreviewPages预览窗口中显示页的初始数量(1或2) l m_rectDraw设定当前页的可用矩形区域,可以缩小该区域以留出空间给页眉和页脚l m_strPageDesc用于打印预览的页码信息格式字符串,默认为“Page %unPages %u-%un”,其中前一行用于单页模式,后一行用于双页模式。例如:void CTestView:OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* pInfo) pInfo-m_nNumPreviewPages = 2;pInfo-m_strPageDesc = Draw Page %unDraw Pages %u%un;CPrintInfo类的常用成员函数有:l SetMinPage设置文档首页的号码。原型为void SetMinPage( UINT nMinPage );l SetMaxPage设置文档尾页的号码。原型为void SetMaxPage( UINT nMaxPage );l GetMinPage返回文档首页的号码。原型为UINT GetMinPage( ) const;l GetMaxPage返回文档尾页的号码。原型为UINT GetMaxPage( ) const;l GetOffsetPage返回被打印的首页之前的文档页数。原型为UINT GetOffsetPage( ) const;l GetFromPage返回被打印的首页号码。原型为UINT GetFromPage( ) const;l GetToPage返回被打印的尾页号码。原型为UINT GetToPage( ) const;例如,可在显示打印对话框之前,设定对话框中显示的打印范围为28:BOOL CTestView:OnPreparePrinting(CPrintInfo* pInfo) pInfo-SetMinPage(2);pInfo-SetMaxPage(8);return DoPreparePrinting(pInfo);11.2.4 公用打印对话框有两个与打印相关的公用对话框类页面设置对话框类CPageSetupDialog和打印对话框类CPrintDialog,它们都是公用对话框类基类CCommonDialog的派生类,而后者又是从CDialog派生的,参见图5-4。1页面设置对话框类页面设置对话框类CPageSetupDialog,封装了Windows的公用OLE页面设置对话框所提供的服务,用于设置页边距。也可以设置纸张的大小和来源(默认为A4和自动选择),以及打印方向是横向还是纵向(默认为纵向),可以替代打印设置对话框。1)构造函数CPageSetupDialog( DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, CWnd* pParentWnd = NULL );下面的代码使用默认构造函数来创建和显示页面设置对话框(参见图11-8):CPageSetupDialog dlg;dlg.DoModal();图11-8中对话框上部显示的样本页面会随着打印方向和页边距的修改而动态改变。按对话框右下部的“打印机”按钮,会弹出具体打印机的页面设置对话框,参见图11-9。2)PAGESETUPDLG结构可在创建对话框对象之后,调用DoModal显示对话框之前,通过其数据成员m_psd来修改页面设置对话框的初始参数。m_psd是一个PAGESETUPDLG结构变量:图11-8 使用默认参数构造的Windows标准页面设置对话框图11-9 具体打印机的页面设置对话框typedef struct tagPSD / psd DWORDlStructSize; / 本结构的大小(字节数) HWNDhwndOwner; / 父窗口的句柄(可为NULL)HGLOBALhDevMode; / 包含打印机的设备与环境信息的/ DEVMODE结构的句柄HGLOBALhDevNames; / 包含驱动器名、打印机名和输出端口名的/ 设备名结构DEVNAMES的句柄 DWORDFlags; / 用于页面设置公用对话框初始化的标志位 POINTptPaperSize; / 用户选择的纸张大小RECTrtMinMargin; / 指定四个页边距的最小允许宽度,若没有设置/ PSD_MINMARGINS标志位,则忽略该值RECTrtMargin; / 指定四个页边距的宽度,若设置了PSD_MARGINS / 标志位,则系统将该值作为页边距的初始值 HINSTANCEhInstance; / 以下结构成员少用 LPARAMlCustData; LPPAGESETUPHOOKlpfnPageSetupHook; LPPAGEPAINTHOOKlpfnPagePaintHook; LPCTSTRlpPageSetupTemplateName; HGLOBALhPageSetupTemplate; PAGESETUPDLG;其中:rtMargin、rtMinMargin和ptPaperSize值的单位由标志位的PSD_INTHOUSANDTHS OFINCHES或PSD_INHUNDREDTHSOFMILLIMETERS指定,DEVMODE结构的定义为:typedef struct _devicemode / dvmd BCHAR dmDeviceNameCCHDEVICENAME; WORD dmSpecVersion; WORD dmDriverVersion; WORD dmSize; WORD dmDri

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论