9.1 文件的存储与读取 9.2 打印 9.3 实例:所见即所得的打印程序

25
Windows Windows 编编 编编 —— —— 第9 第第第第第 第第第第第 06/08/22 06/08/22 编编编编编编编编 编编编 编编编编编编编编 编编编 9.1 编编编编编编编编 9.2 编编 9.3 编编 编编编编编编编编编编 第第第 第第第第第 第第第 第第第第第 第第 第第 第第第第 编编编编编编编编编编编编编编编编 编编编编编编编编编编编编编编编编编编编编编 编编编编编 编编编 。,一 编编编编编编编编编编编编 CFile 编编编编编编 编编编编编 编编编编编编编编编编编 一。 CPrint Info 编编编编编编编编编编编编编

Upload: nalani

Post on 13-Jan-2016

80 views

Category:

Documents


3 download

DESCRIPTION

第九章 文件与打印. 9.1 文件的存储与读取 9.2 打印 9.3 实例:所见即所得的打印程序. 本章要点 本章介绍如何进行文件的读写和打印。文件的保存和打印是许多应用程序必备的功能,我们在这一章里首先介绍了和文件保存有关的 CFile 类和序列化这一重要概念。然后讲述了和打印有关的 CPrint Info 类和与打印及预览相关的函数。. 返回. 9.1 文件的存储与读取. ( 1 ) 使用 CFile 打开和关闭文件 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.1 文件的存储与读取 9.2 打印 9.3 实例:所见即所得的打印程序

第九章 文件与打印第九章 文件与打印

返回返回

本章要点 本章介绍如何进行文件的读写和打印。文件的保存和打印是许多应用程序必备的功能,我们在这一章里首先介绍了和文件保存有关的 CFile 类和序列化这一重要概念。然后讲述了和打印有关的 CPrint Info 类和与打印及预览相关的函数。

Page 2: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.1 9.1 文件的存储与读取文件的存储与读取( 1 )使用 CFile 打开和关闭文件 BOOL Open ( LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL ) ; 参数 lpszFileName :为欲打开的文件名,文件名可以包含路径和文件名两部分。如“ d:\\bak\\test.txt” , 如果此字符串不包含文件路径,如“ test.bak” ,则系统默认为当前路径,即生成的可执行文件所在目录。 参数 nOpenFlags :用于设置访问模式,指定当打开文件时进行的动作,可以将以下所列模式用按位或“ |” 操作符连接起来。至少应有一个访问模式, modeCreate 是可选的。以下是常用参数列表: CFile::modeCreate :调用构造函数构造一个新文件。 CFile::modeRead  : 打开文件仅供读。 CFile::modeReadWrite : 打开文件供读 / 写。 CFile::modeWrite : 打开文件仅供写。 CFile::typeText : 设置文本文件模式(只能用在子类中)。 CFile::typeBinary :设置二进制文件模式(只能用在子类中)。 参数 pError :是一个异常类的指针,可通过该类和函数的返回值来确定函数是否调用成功。

返回返回

Page 3: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.1 9.1 文件的存储与读取文件的存储与读取

返回返回

例:“如要以只读方式打开当前目录的 test.txt”文件时,一个可能的代码如下:

CFile MyFile; cFileException e; if( !MyFile.open ("test.txt",CFile::modeRead,&e) ) { e->ReportError ( ) ; } 当然,也可直接使用 CFile类的第三个构造函数来创建 CFile类对象并同时打开一个文件,如上面的代码可改为: try { CFile MyFile("test.txt" ,CFile::modeRead) ; …… }catch(CFileException *e) { e->ReportError ( ) ; e->Delete ( ) ; } 关闭一个打开的文件,可使用 Close 函数,该函数不带参数。用户应该养成这样的习惯,打开一个文件并使用完毕后,使用 Close 函数关闭该文件。

Page 4: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.1 9.1 文件的存储与读取文件的存储与读取

返回返回

( 2)文件的读写操作 virtual UINT Read (void* lpBuf, UINT nCount) ; throw(CFileException);

Read 函数返回值是传输到缓冲区的字节数。 参数 lpBuf :指向用户提供的缓冲区以接收从文件中读取的数据。 参数 nCount :为可以从文件中读出字节数的最大值。 注意:对所有 CFile 类,如果到达文件尾,则返回值可能比 nCount 小。

virtual void Write(const void* lpBuf, UINT nCount); throw (CFileException);

Write 函数的参数与 Read 函数的参数类似。 参数 lpBuf :指向用户提供的缓冲区,包含将写入文件中的数据。 参数 nCount :从缓冲区内传输的字节数。Write 在几种情况下均产生异常,包括磁盘满的情况、磁盘为写保护状态等。 注意: CFile 类并没有提供类似 EOF 之类的文件结束标志,所以文件的结束是根据Read 函数的返回值来判断的。 Read 函数返回的是实际读出的字符数,当返回 0 时,则表示文件已读完。

Page 5: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.1 9.1 文件的存储与读取文件的存储与读取

返回返回

举个例子,假设现在要把当前目录下的文件 test1.txt 里的数据添加到 testf2.txt 文件尾,则一个可能的实现代码如下: try

{

CFile File1 ("test1.txt",CFile::modeRead) ;

CFile File2 ( "test2.txt",CFile::modeWrite) ;

" char pBuf[256] ;

int strLen =0;

File2.SeekToEnd( ) ;

While((strLen=File1.Read(pBuf,256) )>0)

File2.Write(pBuf. strLen) ;

File1.Close( ) ;

File2.Close( ) ;

}catch(CFileException *e) {

e.ReportError ( ) ;

}

Page 6: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.1 9.1 文件的存储与读取文件的存储与读取

返回返回

( 3)文件的定位 文件定位涉及到一个基本的概念:文件指针。文件指针是指文件当前的读写位置。如打开一个文件用于读取时,文件指针通常指向文件的开头的第一个字符;以后每读一个字符,文件指针会自动向后偏移一个位置,以指向下一个字符。 CFile 类提供了很多成员函数用于提供文件指针的信息以及手动设置文件指针的位置,从而可以实现按需要从文件的任意位置读写文件。 成员函数 GetLength 用于返回打开文件的字节长度, GetPosition 函数用于返回文件指针的当前位置。这两个函数的原型如下: virtual ULONGLONG GetLength( ) const;

virtual ULONGLONG GetPosition( ) const;

有一组函数提供文件定位功能,它们是 SeekToBegin 、 SeekToEnd 和 Seek 函数。函数 SeekToBegin 用于把文件指针移动到文件的开始位置,它的函数原型如下: void SeekToBegin( );

函数 SeekTOEnd 用于把文件指针移动到文件尾。若要在文件末尾添加数据,则常用到这一个函数。它的原型如下: ULONGLONG SeekToEnd( );

其中它的返回值为文件的字节长度。

Page 7: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.1 9.1 文件的存储与读取文件的存储与读取

返回返回

最后还有一个功能最强大的函数是 Seek 函数,它可以把文件指针移动到文件的任何位置。它的原型如下: virtual ULONGLONG Seek(LONGLONG loff,UINT nFrom);

参数 loff 用于指定文件指针的偏移量,而 nFrom 用于指定文件指针的起始位置,下表列出了它的几种取值及其含义。其返回值表示定位后文件指针离文件头的偏移量。

取值 取值 含义 含义 CFile::begin CFile::begin 文件指针从文件头开始移动指定的字节数,也即移动文件指针从文件头开始移动指定的字节数,也即移动 loffloff 个字节数 个字节数 CFile::currenCFile::current t 文件指针从当前位置开始移动指定的字节数 文件指针从当前位置开始移动指定的字节数

CFile::end CFile::end 文件指针从文件尾开始移动指定的字节数时文件指针从文件尾开始移动指定的字节数时 loffloff 参数一般为一个负参数一般为一个负值 值

需要注意的是,如果用 Seek函数定位后文件指针离文件头的偏移量要大于文件的长度,则该函数并不会产生异常,相反,文件的长度会自动扩充成文件指针的偏移量值。如假设文件长度为 1000字节,而用 Seek函数把文件指针定位到离文件头偏移 1050字节的位置时,文件长度便自动变为 1050字节了。

Page 8: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.1 9.1 文件的存储与读取文件的存储与读取

返回返回

( 4)序列化与 CArchive 类 序列化又叫串行化,即 Serialize 。序列化是实现文件保存的必经过程。 MFC 的 CObject派生类都是支持序列化的。如果用户自定义一个需要保存的类,就必须使之序列化。要让用户定义的类支持序列化,一般分为 5步: ( 1 )从 CObject 或其派生类中派生出用户的类。 ( 2 )重载 Serialize() 成员函数,加入必要的代码,用以保存对象的数据成员到CArchive 对象以及从 CArchive 对象载入对象的数据成员状态。 ( 3 )在类声明文件中,加入 DECLARE_SERIAL宏。编译时,编译器将扩充该宏,这是序列化对象所必需的。 ( 4 )定义一个不带参数的构造函数。 ( 5 )在实现文件中加入 IMPLEMENT_SERIAL宏。

Page 9: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.1 9.1 文件的存储与读取文件的存储与读取

返回返回

class CPInfo:public CObject

{

public:

DECLARE_SERIAL(CPInfo)

CPInfo(){}; // 必须提供一个不带任何参数的空的构造函数public:

CString strIncome;

CString strKind;

BOOL bMarried;

CString strName;

int nSex;

CString strUnit;

int nWork;

UINT nAge;

void Serialize(CArchive&);

}

例如,下面用户自定义的一个 CObject 的派生类,叫做 CPInfo 类,它可以保存一些个人注册信息,比如姓名、收入、人种、工作等。

Page 10: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.1 9.1 文件的存储与读取文件的存储与读取

返回返回

void CPInfo::Serialize(CArchive& ar)

{ // 首先调用基类的 Serialize()方法。CObject::Serialize(ar);

if(ar. IsStoring())

{ ar<<strIncome;

ar<<strKind;

ar<<(int)bMarried;

ar<<strName;

ar<<nSez;

ar<<strUnit;

MFC 在从磁盘文件载入这些对象状态并重建对象时,这里需要有一个默认的不带任何参数的构造函数,序列化对象将用该构造函数生成一个对象,然后调用 Serialize() 函数,用重建对象所需的值来填充对象的所有数据成员变量。构造函数既可以声明为 public ,也可以声明为 protected 或 private 。从上面的例子中我们可以注意到,序列化函数所带的参数是一个文件类的对象,我们一般使用 CArchive 类。CArchive 类提供了一个 IsStoring() 成员函数,它指示了是将数据保存到磁盘文件还是从磁盘文件载入对象。例如,实现上面 CPInfo 类的序列化:

Page 11: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.1 9.1 文件的存储与读取文件的存储与读取

返回返回

ar<<nWork;

ar<<(WORD)nAge;

}

else

{

ar>>strIncome;

ar>>strKind;

ar>>(int)bMarried;

ar>>strName;

ar>>nSex;

ar>>strUnit;

ar>>nWork;

ar>>(WORD)nAge;

}

}

很显然,对象的序列化实际上是通过调用对象中的数据成员的序列化来完成的。

Page 12: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.2 9.2 打 印打 印

返回返回

(1) 建立一个支持打印的框架 先看看建立框架时如何使之支持打印和预览功能,在应用程序向导创建多文档应用程序的【高级功能】选项面板中,有一个【打印和打印预览】复选框,将其选中即可,这时打印功能就可以被启用,如图 9-1 所示。

Page 13: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.2 9.2 打 印打 印

返回返回

事实上,即使我们没有刻意地去选择选择这一项,应用程序向导也能够帮助我们完成,因为默认的选项就是支持打印。这里只是通过再次回顾,以确定和理解我们在哪一步完成了建立支持打印的应用程序框架的工作。我们发现,在生成的应用程序框架界面里,【文件】菜单里面多了 3 个【打印】、【打印预览】和【打印设置】这 3 个命令,如图 9-2 所示。

Page 14: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.2 9.2 打 印打 印

返回返回

一般来说,一个MFC 应用程序的打印工作一般是按如下步骤进行的:( 1 ) 首先显示 Print 对话框。( 2 ) 创建一个与当前打印机设置相匹配的图形设备( CDC )对象。( 3 ) 设置要打印的页数,调用 CDC::StartDoc开始打印。( 4)用 CDC::StartPage 开始打印一页;调用视图的 OnDraw() 方法打印输出一页内容     用 CDC::EndPage 结束一页的打印,循环输出全部内容。( 5) 用 CDC::EndDoc结束打印。( 6) 视图作打印的清理工作。 需要注意的是,应用程序向导自动生成了上面打印和打印预览的代码。但是许多情况下,并不能符合要求。这是因为: 首先,打印机和窗口(屏幕)显示的分辨率不同。打印机的分辨率用单位平方英寸面积上有多少黑点来描述,屏幕分辨率用单位面积有多少像素点来表示。在编辑器程序中,使用的映射模式为 MM_TEXT。在这种模式下,一个逻辑单位对应于一个像素点。Windows又是按照逻辑单位来进行绘图的。这样,根据 MM_TEXT模式的逻辑单位(实际上也就是像素数目)决定比例的原则打印出来的内容自然要比屏幕上看到的要小得多。  提示:在初始化视图 OnInitialUpdate 时候,在选择绘图的映射模式上,不要采用以前使用的默认的 MM_TEXT模式,而要采用MM_LOENGLISH。

Page 15: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.2 9.2 打 印打 印

返回返回

此外,窗口和打印机对边界的处理不同。窗口可以看做是无边界的,可以在窗口外面画,而不会引起错误,窗口会自动剪裁超出边界的图形。但打印机却不同,它是按页打印的。打印输出时必须自己处理分页和换页,如果不做这样的处理的话,行和行之间就会叠加起来。 要正确打印输出屏幕上的内容,就必须解决以上两个问题。对于前一个问题,有两种方法可以解决:一是利用 SetMapMode ( int nMode )设置别的映射模式,比如采用MM_LOENGLISH,不用像素而是采用英寸来衡量。

对于第 2 个问题,要处理打印分页、换页,就必须修改框架处理打印消息的默认行为,在其中计算和换页。此外,我们还希望在打印时在页眉处能够输出标题(使用文件名作为标题),在页脚处输出页码。

Page 16: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.2 9.2 打 印打 印

返回返回

(2)CPrintInfo 类与打印相关函数 在完成一个支持打印的程序框架的创建以后,我们很快就会发现,在与打印相关的函数中会有一个 CPrintInfo 类型的对象或该对象指针。这个对象用来维护打印作业或打印预览作业的信息,用于应用程序视图与 MFC 的内置打印函数之间的信息交换。在打印的时候,这个对象在 MFC框架类和视图类之间传递。下表列出了 CPrintInfo 类的最常用数据成员。

成员变量 成员变量 说明 说明

m_nCurPage m_nCurPage 用于标识当前打印的这一页 用于标识当前打印的这一页

m_nNumPreviewm_nNumPreviewPage Page 用于标识打印预览框中显示的页数用于标识打印预览框中显示的页数

m_bPreview m_bPreview 用于指明文档是否正在预览用于指明文档是否正在预览

m_bDirect m_bDirect 用于指明是否直接打印该文档(不通过打印对话框的用于指明是否直接打印该文档(不通过打印对话框的提示)提示)

m_rectDraw m_rectDraw 用于设定可以用于打印的页面区域用于设定可以用于打印的页面区域

Page 17: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.2 9.2 打 印打 印

返回返回

下面介绍一下MFC 的打印体系结构,即打印功能是怎样通过相关函数实现的。框架的打印文档功能是从 OnPreparePrinting(CPrintInfo* pInfo)开始的,在默认的情况下,它只是简单地调用视图的 DoPreparePrinting()函数。 DoPreparePrinting() 显示 Print 对话框,并创建与打印机相匹配的设备上下文。如果要想改变打印机初始设置,可以在这里改。例如,我们希望某个文档分两页打印:第 1页为封面,打印文档名字;第 2页输出文档内容,并在页眉上打印文档名字。默认设置下,使用 1 作为第 1页编号,用 0xFFFF 作为文档的最后一页编号。因为要求分两页打印输出,因此要在这里设置打印页数。要设置打印页数,可以调用函数 CPrintInfo::SetMaxPage(nMaxPage)。通过设置 CPrintInfo 对象的 m_nNumPreviewPage 成员变量,还可以将预览页数也设置为两页。参考如下代码:BOOL CDrawView::OnPreparePrinting(CPrintInfo* pInfo){pInfo->SetMaxPage(2); //这个文档有两页//并且处页作为标题页,第 2页为需要打印的页BOOL bRet = DoPreparePrinting(pInfo); //默认设置pInfo->m_nNumPreviewPages=2; //每次预览两页return bRet;}

Page 18: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.2 9.2 打 印打 印

返回返回

DoPreparePrinting 显示 Print 对话框。返回时, CPrintInfo 结构包含了用户所指定的值,包括起止页号、最大页号、最小页号等。OnBeginPrinting()在 OnPreparePrinting() 被调用之后实际打印之前调用。 OnBeginPrinting()用于分别GDI资源。OnPrepareDC 用做屏幕显示时,在绘图前调整 DC 。在用于打印时, OnPrepareDC也完成类似功能。OnPrint 完成真正的打印一页文档的工作。它把一个打印机设备上下文传给视图类对象的 OnDraw函数,由OnDraw负责打印输出。可以把那些适合于打印但是不适合于屏幕输出的工作,如打印页眉和页脚,放在 OnPrint()的重载中完成,然后再调用 OnDraw完成打印和显示都需要的工作。 OnPrint()不是由应用程序向导自动生成的,要用类向导为视图类对象增加OnPrint() 方法,然后添加绘图程序的特殊打印打印代码。参考以下代码,在 OnPrint 中加入打印页眉和页脚的代码。void CDrawView::OnPrint(CDC* pDC, CPrintInfo* pInfo){//第 1页是封面if (pInfo->m_mCurPage = =1){PrintTitlePage(pDC, pInfo);

Page 19: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.2 9.2 打 印打 印

返回返回

//在第 1页上只打印标题return;}//打印页眉 CString strHeader=GetDocument()->GetTitle();PrintPageHeader(pDC, pInfo, strHeader); //自定义的打印页眉函数//调整正文区域位置和大小pDC->SetWindowOrg(pInfo->m_rectDraw. left. –pInfo->m_rectDraw, top);//打印正文OnDraw(pDC);}OnPrint() 首先根据 CPrintInfo 类的 pInfo 中 m_nCurPage (保存当前打印页号信息)判断当前打印是不是第 1页。如果是第 1页,就打印输出封面。否则,首先调用PrintPageHeader打印页眉,然后用 SetWindowOrg调整打印输出的原点位置。 m_rectDraw又是 CPrintInfo结构的一个重要数据成员,它保存的是打印输出的矩形边界。最后将与打印机匹配的设备上下文传给 OnDraw,由 OnDraw在打印面上输出。注意:这里使用的映射模式为MM_LOENGLISH,它的 Y 轴方向是向上递增的。

Page 20: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.39.3 实例:所见即所得的打印程序实例:所见即所得的打印程序

返回返回

实例说明:MFC 几乎做了打印文档所需要的全部工作,而且,打印预览已与由MFC 应用程序向导所生成的应用程序合并在一起,这使得用户几乎无需编写任何代码,即可创建一个支持打印和打印预览功能的应用程序。以下将演示如何创建一所见即所得的打印程序。本实例创建一个具有全部打印功能应用程序,该程序不仅可以在它的主窗口显示它的数据(矩形),而且在一个打印预览的窗口中和打印机上都可以显示和打印输出。用户可以通过鼠标的左、右击来增加和减少矩形的数目。该程序在打印预览窗口中的效果如下图所示。学习目标:在本例中,用户主要应学会如何创建一个支持打印和打印预览功能的应用程序,如何设置设备环境的映射模式,以及如何动态增减矩形的个数

Page 21: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.39.3 实例:所见即所得的打印程序实例:所见即所得的打印程序

返回返回

(1) 启动 Visual C++ . NET,新建一个 Visual C++项目,选用 MFC 应用程序模板,项目名称为 PrintExp。(2)在应用程序向导的【应用程序类型】选项中选择【单文档】,同时确保【高级功能】选项中选中【打印与打印预览】项。最后单击【完成】按钮完成项目的建立。分析:此时所创建的应用程序已具有了全部的打印功能,以下将主要为此应用程序 构造输出数据(矩形)。(3)为 CPrintExpDoc类添加成员变量m_numRects ,用于保存显示矩形的个数。 Public: int m_numRects;(4)为 CPrintExpDoc类的构造函数添加代码,用于设置初始时显示矩形的个数。 CPrintExpOoc : : CPrintExpDoc ( ) { m_numRects=5; }(5)为 CPrintExpView类添加鼠标单击消息的映射函数。在【类视图】窗口中,右击 CPrintExpView类调出【属性】窗口,选择【消息】选项卡,从中添加WM_LBUTTONDOWN与WM_RBUTTONDOWN的消息处理函数。(6) 编写 OnLButtonDown()函数,用于单击鼠标左键时,增加显示矩形的数目。 void CPrintExpView: : OnLButtonDown (UINT nFlags, CPoint point )

Page 22: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.39.3 实例:所见即所得的打印程序实例:所见即所得的打印程序

返回返回

{ // TODO:在此添加消息处理程序代码和/或调用默认值 //获取 CPrintExpDoc类的指针 CPrintExpDoc * pDoc=GetDocument ( ) ; ASSERT_VALID (pDoc) ; //使显示矩形数目加一 pDoc->m_numRects++ ; //更新显示 Invalidate () ; CView: :OnLButtonDown (nFlags, point);}(7) 编写 OnRButtonDown()函数,用于单击鼠标右键时,减少显示矩形的数目。 void CPrintExpView: :OnRButtonDown (UINT nFlags, CPoint point} { // TODO:在此添加消息处理程序代码和/或调用默认值 //获取 CPrintExpDoc类的指针 CPrintExpDoc " pDocEGetDocument ( ) ; ASSERT VALID (pDoc) ;

Page 23: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.39.3 实例:所见即所得的打印程序实例:所见即所得的打印程序

返回返回

//使显示矩形数目减一 if (pDoc->m_numRects>0 ) { pDoc->m_numRects-- ; //更新显示 Invalidate( ) ; } CView: :OnRButtonDown (nFlags, point) ; }(8) 编写 CPrintExPView类的 OnDraw()函数,用于绘制矩形和显示矩形数目。 void CPrintExpView: :OnDraw (CDC* pDC) { CPrintExpDoc* pDoc=GetDocument () ; ASSERT VALID (pDoc) ; // TODO:在此处为本机数据添加绘制代码 //设置设备环境的映射模式 pDC->SetMapMode (MM_LOENGLISH) ;

Page 24: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.39.3 实例:所见即所得的打印程序实例:所见即所得的打印程序

返回返回

//显示矩形的数目 CString numbers; numbers . Format ( "&d" , pDoc->m_numRects ) ; pDC->TextOut (300, -100, numbers) ; //绘制矩形 ror (int x=0 ; x<pDoc->m_numRects ; ++x) { pDC->Rectangle (20, - (20+x*220) , 220, - (220+x*220) ) ; }}分析:映射模式用于定义逻辑坐标的单位与设备坐标间的关系。在默认的映射模式 MM_TEXT下,把每个逻辑单位映射成一个设备像素, X 轴正方向朝右, Y轴正方向朝下。但在 MM_TEXT 映射模式下,有可能使打印的文档和屏幕上显示的文档不同,这是由于屏幕上的像素和打印机上的点尺寸不同。为了避免当打印机和屏幕的一页容纳不同的像素时引起的问题,一种较好的图形映射方式为MM_LOENGLISH,它使用百分之一英寸而非一点或一个像素作为计量单位,在这种映射模式下, X 轴正方向朝右, Y 轴正方向朝上。至此,程序编写完成,编译并运行它,在应用程序中,试着单击鼠标左、右键以改变显示矩形的数目。

Page 25: 9.1   文件的存储与读取 9.2   打印 9.3   实例:所见即所得的打印程序

《 《 WindowsWindows 编程编程》——》——第第 99 章 文件与打印章 文件与打印

04/21/2304/21/23民政学院软件学院 蒋国清民政学院软件学院 蒋国清

9.39.3 实例:所见即所得的打印程序实例:所见即所得的打印程序

返回返回

当用户单击【文件】菜单下的【打印预览】项时,将会显示【打印预览】窗口。当窗口中显示的矩形数目超过 6时,在一页中将无法显示所有的矩形。此时,若用户在【打印预览】窗口选择【两页】按钮,发现此程序并不能支持多页打印功能,第二页尚为空,如下 图所示。