Visual C++程序设计与应用教程(下).ppt_第1页
Visual C++程序设计与应用教程(下).ppt_第2页
Visual C++程序设计与应用教程(下).ppt_第3页
Visual C++程序设计与应用教程(下).ppt_第4页
Visual C++程序设计与应用教程(下).ppt_第5页
已阅读5页,还剩293页未读 继续免费阅读

下载本文档

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

文档简介

1、1,Visual C+程序设计与应用,主编 马石安 魏文平,清华大学出版社,2,主要内容,第1章 Visual C+开发环境 第2章 MFC应用程序 第3章 图形与文本 第4章 菜单、工具栏与状态栏 第5章 对话框 第6章 Windows常用控件,第7章 文档与视图 第8章 打印编程 第9章 动态链接库编程 第10章 多线程编程 第11章 数据库编程 第12章 多媒体编程,第 5 章 对话框 5.1 对话框概述 5.2 模式对话框 5.3 非模式对话框 5.4 属性页对话框 5.5 通用对话框 5.6 应用实例,Visual C+程序设计与应用教程,4,5.1 对话框概述,5.1.1 对话框的

2、类型,主要有以下两种: 模式(Model)对话框 无模式(Modeless)对话框,5,5.1.2 对话框的CDialog类,CDialog类从CWnd类派生而来,所以它继承了CWnd类的成员函数,具有CWnd类的基本功能,可以编写代码移动、显示或隐藏对话框,并能根据对话框的特点增加新的成员函数,扩展它的功能。,6,7,8,对话框主要由以下两部分组成: (1) 对话框模板:对话框模板定义了对话框的特性(比如大小、位置和风格)以及对话框中每个控件的类型和位置。 (2) 对话框类:从CDialog类派生的对话框类提供编程接口来管理对话框。,5.1.3 对话框的组成,9,5.2 模态对话框,对于模式

3、对话框的编程可以按以下步骤进行。 (1) 根据要求创建对话框模板。 (2) 使用ClassWizard创建对话框类并进行各类事件函数的代码编写。 (3) 对视图类进行编辑,以便对话框能够被激活。,10,5.2.1 设计对话框模板资源 打开对话框编辑器: 使用菜单【Insert|Resource】打开Insert Resource对话框,选中Dialog后单击New按钮。 使用项目的ResourceView,找到Dialog资源,右击后选择Insert Dialog。 对话框编辑器如下图所示。,11,对话框模板,控件布局工具栏,控件工具栏,12,对话框模板,Controls工具,Dialog工具

4、栏,调整对话框显示时的大小和位置,拖放各种类型的控件到对话框中,调整控件的位置,测试对话框的外观和行为,13,设计对话框模板资源有两个重要的内容: 从Controls工具栏中选择控件(Control,功能各异的小小零组件)加到对话框中,并调整其位置和大小 设置控件的Caption、ID以及其他属性,14,1增加或删除控件,增加控件: 从控件工具栏中选中要增加的控件,再将此控件拖动至对话框模板中的确定位置上 删除控件: 先单击对话框中的控件,再按Delete键,15,2设置控件属性,属性设置在与每个控件相对应的属性对话框中进行。 打开控件属性对话框: 在控件上右击鼠标,在弹出的快捷菜单中选择Pr

5、operties 选择控件,选择View|Properties菜单项,16,控件属性对话框,17,对话框的属性也是在对话框的属性对话框中设置。 在对话框任意空白处单击鼠标右键,在弹出的快捷菜单中选择Properties 。,18,3测试对话框的运行效果 测试对话框的方法有下面3种: 选择菜单项Layout |Test。 单击布局工具栏上的Test按钮。 按快捷键Ctrl+T。,19,【例5.1】创建一个单文档的应用程序MyDialog,向应用程序中添加如图所示的对话框模板资源,并设置控件的Caption、ID属性。,20,5.2.2 设计对话框类,主要包括下面几个方面: 从MFC的CDialo

6、g中派生出一个类,用来负责对话框行为。 利用ClassWizard把这个类和已编辑完成的对话框资源连接起来。 这意味着必须声明某些函数,用以处理相应的对话框消息,并将对话框中的控件对应到类的成员变量上,这也就是所谓的对话框数据交换(DDX,Dialog Data eXchange)。如果对这些变量内容有“确认规则”的话,ClassWizard也允许设定,这就是所谓的对话框数据验证(DDV,Dialog Data Validation)。 对话框的初始化。,21,1.创建对话框类 【例5.2】完善例5.1中的应用程序MyDialog,给对话框资源添加相应的对话框类。,22,2.创建对话框成员变量

7、,ClassWizard类向导的Member Variables页面用来为对话框类添加和删除与对话框控件关联的成员变量。,23,【例5.3】继续完善例5.2中的应用程序,在对话框类中添加与控件相关联的成员变量。,24,3对话框的初始化,使用以下3种方法: (1) 在构造函数中初始化 主要针对对话框的数据成员。 (2) WM_CREATE初始化 (3) WM_INITDIALOG初始化,25,5.2.3 运行对话框,模态对话框的运行分两个步骤: 创建一个对话框对象 调用CDialog:DoModal()函数打开对话框 DoModal()函数负责模态对话框的创建和撤消,可以根据其回值是IDOK还是

8、IDCANCEL来判断用户关闭对话框时按的哪一个键。,26,【例5.4】完善例5.3中的应用程序,通过【对话框|模态对话框】菜单项,打开上述标题为“输入边长”的对话框,并根据输入的边长画一个正方形。,27,5.2.4 对话框数据交换和校验机制,CDialog类通过调用其成员函数DoDataExchange()实现对话框数据交换和验证,在DoDataExchange()中使用了MFC提供的CDataExchange类,该类实现对话框类的成员变量与控件之间的数据交换DDX和数据验证DDV。 DDX将成员变量与对话框控件相连接,完成数据在成员变量和控件之间的交换。DDV用于数据的校验,它能自动校验输

9、入的数据(如字符串的长度或数值的范围)是否符合设计要求。,28,DoDataExchange()函数由框架调用。在应用程序MyDialog中,可以找到下列函数: void CSquare:DoDataExchange(CDataExchange* pDX) CDialog:DoDataExchange(pDX); /AFX_DATA_MAP(CSquare) DDX_Text(pDX, IDC_LENGTH, m_length); DDV_MinMaxInt(pDX, m_length, 10, 200); /AFX_DATA_MAP ,DDX函数调用语句,表明m_length是一个Value

10、值类别的成员变量,用于交换IDC_LENGTH控件中内容,DDV函数调用语句,程序运行后,如果用户的输入数据超出10200的范围,DDV将显示提示信息对话框,提示用户有效的输入范围,29,控件与成员变量之间的数据交换通过调用UpdateData()函数进行。 UpdateData()函数只有一个BOOL类型的参数 当参数为TRUE时,MFC通过调用DoDataExchange()函数将数据从控件传递到关联的成员变量 当参数为FALSE时,数据从成员变量传递到关联的控件。 如下图所示。,30,31,5.3 非模态对话框,5.3.1 非模态对话框的特点,与模态对话框比较: 相同:创建对话框资源、添

11、加对话框类、添加成员变量和消息处理函数的方法 不同:创建和退出对话框的方式,32,1.Visible属性 模态对话框不需要设置该属性,而非模态对话框必须具有Visible风格,否则对话框是不显示的。 另一种方法是调用CWnd:ShowWindow(SW_ SHOW)来显示对话框。,33,2.对话框窗口的创建方式 非模态对话框的创建是通过调用CWnd:Create()函数来实现的。 Create()函数与DoModal()函数不同之处是:Create()创建对话框后立即返回,而DoModal()函数在对话框关闭后才会返回。,34,3.对话框对象的创建方式 由于在Create()返回后,不能确定对

12、话框是否已关闭,这样也就无法确定对话框对象的生存期,所以不能以局部变量的形式创建非模态对话框的对象,只能用new操作符动态创建,并且在调用对话框类的窗口类内声明一个指向对话框类的指针变量,通过该指针访问对话框对象。,35,4.窗口删除函数 非模态对话框必须调用CWnd:DestoryWindow()来关闭对话框。 模态对话框是调用CDialog:EndDialog()关闭对话框。由于默认的对话框函数OnOK()和OnCancel()都是调用EndDialog()关闭对话框的,该函数使对话框不可见但不删除对话框对象。所以非模态对话框类要定义自己的OnOK()和OnCancel()函数,调用Des

13、toryWindow()来关闭对话框。,36,5.清理对话框对象的方式 与创建对象的方式new操作相对应,使用delete操作删除一个非模态对话框对象。 当屏幕上一个窗口被关闭后,框架会自动调用CWnd:PostNcDestroy()函数,也可以编写程序代码,在这个函数中清理非模态对话框对象。,37,6. 必须有一个标志表明非模态对话框是否是打开的 因为在非模态对话框打开的情况下,用户有可能再次选择打开该对话框,这时不能再创建一个新的非模态对话框。 程序根据标志来判断是打开一个新的对话框还是激活一个已打开的对话框。通常可以用拥有者窗口中的指向对话框对象的指针作为这种标志,当对话框关闭时,给该指

14、针赋NULL值,以表明对话框对象已不存在了。,38,【例5.5】创建一个单文档的MFC应用程序,以非模态对话框的形式实现应用程序MyDialog同样的功能。,39,5.3.2 窗口对象的自动清除(自学),40,5.4 属性页对话框,属性页对话框实际上是一个包含了多个子对话框的对话框,这些子对话框通常被称为页(Page)。每次只有一个页是可见的,在对话框的顶端有一行标签,用户通过单击这些标签可以切换到不同的页。 为了支持属性页对话框,MFC提供了CPropertySheet类和CPropertyPage类。分别代表属性页对话框和对话框中的某一页。,41,【例5.6】创建一个单文档的MFC应用程序

15、Li5_6,通过【对话框|属性页对话框】菜单项,打开如图所示的对话框。当按确定按钮后,将在消息框中输出相关信息。,42,【例5.6】使用CpropertySheet派生类对象来创建与例5.5同样的属性页对话框。,43,5.5 通用对话框,44,5.5.1 CFileDialog类,用CFileDialog类提供的通用文件对话框,实现Windows标准的【打开】和【另存为】功能。,45,使用CFileDialog可按以下步骤进行。 构造CFileDialog类的对象。该类的构造函数为: CFileDialog( BOOL bOpenFileDialog,值为TRUE,构造【打开】对话框;值为 F

16、ALSE,构造“另存为”对话框 LPCTSTR lpszDefExt=NULL,默认的文件扩展名 LPCTSTR lpszFileName=NULL,出现在文件名编辑框中的初始文件名 DWORD dwFlags=OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter=NULL,CWnd *pParentWnd=NULL文件过滤器, 用于确定显示在文件列表中的文件类型 ),46,例如,以下字符串就是一个描述只在文件列表框中显示文本文件(*.txt)和Microsoft文件(*.doc)的过滤器。 CFileDialog dlg(TRU

17、E,bmp,*.bmp, OFN_HIDEREADONLY |OFN_ALLOWMULTISELECT,文本文件(*.txt)|*.txt|Word文件(*.doc)|*.doc|); 第1个参数TRUE:【打开】对话框; 第2个参数“bmp”:如果在文件名对话框中输入文件名时未指定扩展名,则会自动附加“.bmp”; 第3个参数“*.bmp”:文件名对话框中的初始文件名是*.bmp; 第4个参数代表dwFlags:不显示隐藏文件,且可以在列表框中进行多选;第5个参数是过滤器:在文件类型下拉列表框中显示了文本文件(*.txt)和Word文件(*.doc)。,47,(2) 调用成员函数DoModa

18、l( ),将对话框显示在屏幕上,并让用户从中选择文件。 (3) 如果DoModal( )返回的是IDOK,那么调用下表中的成员函数获取文件信息。,48,【例5.7】创建一个单文档的MFC应用程序Li5_7,利用文件存取对话框取得一个文件的路径名。,49,5.5.2 CColorDialog类,CColorDialog类提供了可以选择颜色的对话框,使得用户可以从颜色列表中选择要用的颜色。 对该类的使用可按下列步骤进行: (1) 在视图类相应位置构造CColorDialog对象。 (2) 设置或修改成员变量m_cc来初始化对话框。m_cc的结构类型为COLORREF。 (3) 调用成员函数DoMo

19、dal()来显示对话框并让用户从中选择颜色。,50,(4) 如果DoModal()返回的是IDOK,那么用户所做的颜色选择将保存在m_cc中。通过使用该类的成员函数GetColor()即可得到选择颜色的RGB值。 【例5.8】创建一个单文档的MFC应用程序Li5_8,利用颜色选择对话框选择颜色,并在视图区画一个该颜色的矩形。,51,5.5.3 CFontDialog类,CFontDialog类封装了标准的【字体】对话框,使得用户可以从系统安装的字体列表中选择要用的字体。 CFontDialog类的使用步骤与CColorDialog的使用过程是一样的,只是m_cc的结构类型为LOGFONT。 在

20、选择了字体后,可通过下表中的成员函数获取所选择的字体信息。,52,53,【例5.9】创建一个单文档的MFC应用程序Li5_9,利用字体选择对话框选择字体的属性,并在视图区以该属性显示文本信息。,54,5.5.4 CPrintDialog类和CPageSetupDialog类 CPrintDialog类支持打印和打印设置对话框,通过这两个对话框用户可以进行与打印有关的设置。,55,5.5.5 CFindReplaceDialog类 CFindReplaceDialog类用于实现查找和替换对话框。这两个对话框都是非模态对话框,用于在正文中查找和替换指定的字符串。,56,5.6 应用实例,制作一个简

21、单的计算器,实现加、减、乘、除、求倒数和平方根的混合运算,并能进行清屏及倒退操作。,57,第 7 章 文档与视图 7.1 文档/视图结构 7.2 简单的文档/视图结构应用程序 7.3 文档的读写 7.4 分割视图窗口 7.5 多文档的应用程序 7.6 应用实例,Visual C+程序设计与应用教程,58,7.1 文档/视图结构,为了统一和简化数据处理方法,Microsoft公司在MFC中提出了文档/视图结构的概念。 把数据管理和显示方法分离开来,需要考虑: 程序的哪一部分拥有数据 程序的哪一部分负责更新数据 如何以多种方式显示数据 如何让数据的更改有一致性 如何储存数据(放到永久储存装置上)

22、如何管理使用者接口。,59,7.1.1 概述,文档/视图结构的基本概念及创建过程。 (以例 2.1为例) 1.文档(Document) 在文档/视图结构中,文档是用来管理和组织数据的。CDocument类支持文档的标准操作,为了在应用程序中处理文档,首先应该从CDocument类派生出一个属于自己的文档类,并且在类中声明一些成员变量,用来存放数据;然后完成读取和修改文档数据的成员函数;最后再至少重载专门负责文件读写操作的Serialize( )函数。,60,在使用MFC创建新的应用程序框架时,AppWizard准备好了文档类的空壳,下面是应用程序Li2_1中文档类的定义的部分代码:,/ Li2

23、_1Doc.h : interface of the CLi2_1Doc class class CLi2_1Doc : public CDocument/派生出一个属于自己的文档类 protected: CLi2_1Doc(); DECLARE_DYNCREATE(CLi2_1Doc) public: virtual BOOL OnNewDocument(); virtual void Serialize(CArchive,61,2视图 (View),在文档/视图结构中,视图的作用是显示和编辑文档数据,提供用户与文档数据的交互接口。视图在MFC的CView类里被实例化。 在开发应用程序时,应

24、该从CView类派生出一个属于自己的视图类,并且在类中至少改写专门负责显示数据的OnDraw()函数或OnPrint()函数。,62,class CLi2_1View : public CView /派生出一个属于自己的视图类 protected: / create from serialization only CLi2_1View(); DECLARE_DYNCREATE(CLi2_1View) public: CLi2_1Doc* GetDocument(); /得到与之相关联的文档对象的指针 public: virtual void OnDraw(CDC* pDC); / 负责显示数据

25、的OnDraw()函数 virtual BOOL PreCreateWindow(CREATESTRUCT ;,63,CView类和它的9个派生类封装了视图的各种不同的功能,它们为用户实现最新的Windows特性提供了很大的便利。这些派生视图类也可以作为用户程序中视图类的基类,而将这些视图类设置为基类的最基本的方法是在MFC APPWizard创建SDI/MDI的第6步中进行基类的选择。这些视图类如下表所示。,64,65,Frame窗口负责文档与视图的界面管理,当Frame窗口关闭时,在其中的视图也被自动删除。下图说明了文档、视图、框架窗口之间的关系。,3. 框架 (Frame) 窗口,一个视

26、图只能拥有一个文档,但一个文档可以同时拥有多个视图。,66,4.文档模板(Document Template),文档模板定义了文档、视图和框架窗口这3个类的关系。 MFC提供了一个文档模板类CDocTemplate支持文档模板。文档模板类是一个抽象的基类,它定义了文档模板的基本处理函数接口。由于它是一个抽象基类,因此不能直接用它来定义对象而必需用它的派生类。对一个单文档界面程序,使用CSingleDocTemplate类,而对于一个多文档界面程序,使用CMultipleDocTemplate类。,67,5文档/视图结构的产生,一般在应用程序的初始化函数InitInstance()中创建一个和多

27、个文档模板。,68,BOOL CLi2_1App:InitInstance() CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CLi2_1Doc), RUNTIME_CLASS(CMainFrame), RUNTIME_CLASS(CLi2_1View); AddDocTemplate(pDocTemplate); ,69,文档/视图结构的创建过程如下图所示。,70,7.1.2 文档与视图之间的相互作用,文档与视图的交互是通过类的公有成员

28、变量和成员函数实现的。 1视图类CView的成员函数GetDocument() 一个视图对象只有一个与之相关联的文档对象。在MFC应用程序中,视图对象通过调用成员函数GetDocument()得到与之相关联的文档对象的指针,利用这个指针就可以访问文档类及其派生类的公有数据成员和成员函数。,71,2CDocument类的成员函数UpdateAllViews() 一个文档对象可以有多个与之相关联的视图对象,但一个文档对象只反映当前视图的变化。当一个文档数据通过某个视图被修改后,与它关联的每一个视图都必须反映出这种修改。因此,视图在需要时必须进行重绘,即当文档数据发生改变时,必须通知所有相关联的视图

29、对象,以便更新所显示的数据。更新与该文档有关的所有视图的方法是调用成员函数CDocument:UpdateAllViews()。,72,3视图类的成员函数OnUpdate(),当应用程序调用CDocument:UpdateAllViews()函数时,实际上是调用了所有相关视图的OnUpdate()函数,以更新相关的视图。需要时,可以直接在视图派生类的成员函数中调用该函数刷新当前视图。另外,在初始化视图成员函数CView:OnInitialUpdate()中也调用了OnUpdate()函数。 刷新视图时默认的函数调用过程是:Cdocument:UpdateAllViews()CView:OnUp

30、date() CWnd:Invalidate()OnPaint()OnDraw()。,73,4CView类的OnInitialUpdate()函数,当应用程序被启动,或用户从“文件”菜单中选择了“新建”或“打开”命令时,CView的OnInitialUpdate()函数会被调用,该函数是虚函数。 还可以利用派生类的OnInitialUpdate()函数对视图对象进行初始化。当应用程序启动后,应用程序框架在调用了OnCreate()函数后(如果对OnCreate()函数进行了映射),会立即调用OnInitialUpdate()函数。OnCreate()函数只能被调用一次,而OnInitialUp

31、date()函数则可以被调用多次。,74,7.1.3 使用文档视图结构的意义,75,文档视图结构带来的好处主要有: 首先是将数据操作和数据显示、用户界面分离开 MFC在文档/视图结构上提供了许多标准操作界面,包括新建文件、打开文件、保存文件、打印等,减轻了用户的工作量 支持打印预览和电子邮件发送功能,76,7.2 简单的文档/视图结构应用程序,一般的,类的数据成员的初始化都是在构造函数中完成的,在构造函数调用结束时对象才真正存在。但对于文档来说却不同,文档类的数据成员初始化工作是在OnNewDocument()成员函数中完成的。,7.2.1 文档中数据的初始化,77,7.2.2 文档中数据的清

32、理,同文档的初始化类似,文档的清理也不是在文档的析构函数中完成,而是在文档的DeleteContents()成员函数中完成的。,78,7.2.3 简单的文档/视图结构应用程序,【例7.1】编写一个单文档的应用程序Mydraw,程序运行后,当用户在客户区窗口按下鼠标左键时,以鼠标所在位置为圆心绘圆。,79,编译、链接并运行程序。在视图窗口中单击鼠标左键,就可以鼠标所在位置为圆心绘圆。,绘制的图形符合题目要求,但当改变窗口大小或将窗口最小化后再重新打开,原来的圆没有显示出来。其原因是此时调用的是视图类的刷新函数OnDraw(),而在该函数中并没有实现绘圆功能。,80,为了避免上述情况的发生,必须在

33、OnDraw()函数中重绘以前单击鼠标所绘制的圆,因此需要将鼠标单击时的坐标数据保存起来。 下面的例7.2在文档类中定义一个大小为100的points数组来保存圆心坐标数据。,81,【例7.2】完善例7.1应用程序Mydraw,在重绘窗口时能够显示已绘制的圆。,82,7.2.4 集合类的使用,通常使用简单的数组或链表来存储集合数据。MFC提供了相应的集合类,来实现数组、列表和映象操作。,数组类类似于标准的C数组,允许使用下标访问和操作数组元素,MFC数组类还可在需要时,动态地缩减和增加数组所需的内存空间。 列表类就是一个有序元素列表,提供用于在任意地方插入和删除节点,向前、向后遍历元素的功能。

34、 映象类是使用关键字进行访问的对象的集合,类似于字典的组织方式,通过使用哈希(hashing)技术来使映象值与关键字配对,能实现对项目的快速访问。,83,MFC提供了两种集合类: 基于模板的集合类 由这些集合类可以创建任何类型的数组、列表和映象。为了使用这些类,必须在程序中包含头文件“afxteml.h”。 非模板集合类 MFC提供了许多预定义的类,分别用来实现特定类型的数组、列表和映象。,84,各个模板集合类的使用方法与对应的数组类、链表类、映射类的使用方法相同,只需在定义具体的数组类对象或链表类对象、映射类对象时给模板实例化,指定一个具体的类即可。 例如下面的语句定义了一个CPtrArra

35、y类对象: CStringArray m_strText 而下面的语句定义了一个CTypedPtrArray类对象: CTypedPtrArray m_CircleArray,85,【例7.3】编写一个单文档的应用程序Mycircle,利用数组类实现例7.2的功能。,86,7.3 文档的读写,MFC中提供了一种读写文件的简单方法“序列化”(即Serialize ,该函数为虚函数)。 序列化机制通过更高层次的接口功能向开发者提供了更利于使用和透明于字节流的文件操纵方法。 序列化也叫串行化。,87,7.3.1 MFC文档读写机制,1创建文档,2打开文档,88,3保存文档,89,4关闭文档,当用户试

36、图关闭文档(或退出应用程序)时,应用程序会根据用户对文档的修改与否 来进一步完成下列任务: (1) 若文档内容已被修改,则弹出一个消息对话框,询问用户是否需要将文档保存。若用户选择“是”,则应用程序执行OnFileSave()过程。 (2) 调用CDocument:OnCloseDocument()虚函数,关闭所有与该文档相关联的文档窗口及相应的视图,调用文档类CDocument的DeleteContents()清除文档数据。,90,序列化的基本思想是: 一个类应该能够对自己的成员变量的数据进行读写操作,对象可以通过读操作而重新创建。即对象可以将其当前状态(由其成员变量的值表示)写入永久性存储

37、体(通常是指磁盘)中,以后可以从永久性存储体中读取(载入)对象的状态,从而重建对象,类的对象自己应该具备将状态值写入磁盘或从磁盘中读出的方法(即成员函数),这种对象的保存和恢复的过程称为序列化。,7.3.2 MFC文档序列化,91,MFC AppWizard向导生成的Seralize()函数由一个if-else结构组成,例如应用程序Li7_1中有如下代码: void CLi7_1Doc:Serialize(CArchive void CMyPrintView:OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) / TODO: add ext

38、ra initialization before printing void CMyPrintView:OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) / TODO: add cleanup after printing ,118,8.1.2 CPrintInfo类,CPrintInfo类保存了打印和打印预览的相关信息,当用户单击【File】菜单的【打印】或【打印预览】命令时,系统自动创建一个CPrintInfo类对象,用于保存用户打印设置的信息。当打印操作结束时,系统自动删除CPrintInfo类对象。在打印过程中,CPrintInfo类

39、在框架窗口和CView类之间起着消息传递的作用。,119,8.1.3 打印过程,一个打印作业由以下几步构成: (1)如果执行打印预览命令,框架窗口将调用CView:OnPreparePrinting()函数,创建与当前默认打印机相关的设备描述对象,对CPrintInfo类中的一些成员变量赋值或调用类成员函数来控制打印的方式,调用DoPreparePrinting()函数。 如果执行打印命令,DoPreparePrinting()函数将显示打印对话框。在对话框中,用户可 以设置打印范围,选择打印机、打印份数。,120,(2)调用CView:OnBeginPrinting()函数分配打印过程所需要

40、的系统资源。 (3)调用CDC:StartDoc()启动主打印循环。 (4)打印新页时,框架窗口首先调用CView:OnPrepareDC(),在打印之前根据当前打印机的设备描述表进行调整。 如果事先不知道需要打印多少页,则被重载的OnPrepareDC()函数可以检测文档的结束。如果文档结束,将CPrintInfo:m_bContinuePrinting值设置为FALSE,跳到(6);否则,设置CPrintInfo:m_bContinuePrinting的值为TRUE,继续进行打印。,121,(5) 调用CDC:StartPage()、CView:OnPrint()和CDC:EndPage(

41、)进行打印。在默认情况下,OnPrint()函数首先调用OnPrepareDC()函数对坐标进行变换,然后调用OnDraw()函数往打印机里输出数据。 (6) 当m_bContinuePrinting为FALSE时,打印结束。调用CDC:EndDoc()函数释放在 打印过程中占用的各种资源。 (7) 调用OnEndPrinting()函数,结束打印。,122,123,8.1.4 打印预览,打印预览命令的执行可以分成以下几个步骤: 主框架窗口执行OnFilePreparePrint()函数。在OnFilePreparePrint()函数中,执行 OnPreparePrinting(CPrintl

42、nfo*pInfo)函数,检测m_bPreview变量是否为TRUE。如果是,则对CPrintInfo类中的一些成员变量赋值或调用类成员函数来控制打印预览的方式。 调用CView:DoPreparePrinting()函数,显示打印预览界面。 调用OnDraw()函数按照打印机的设备描述表往屏幕输出数据,利用屏幕来模拟显 示打印结果。,124,8.2 设置打印坐标系,8.2.1 Windows映射模式,Windows映射模式就是Windows下的坐标方式。在Windows操作系统中,存在两种类型的坐标:设备坐标和逻辑坐标。当向设备输出图形时,Windows先映射当前逻辑坐标到物理坐标(例如打印

43、机),然后显示图形输出。,125,126,8.2.2 映射模式的设置,在MFC应用程序中,通过调用CDC类的SetMapMode()函数设置映射方式。如在视图类的OnDraw()函数中,可以通过以下代码设置映射方式: pDC- SetMapMode(n); 其中,n为上表中列出的映射方式。,127,【例8.2】完善例8.1中的程序MyPrint,使打印输出的图形与显示器显示的图形大小基本一样。,128,8.3 多页打印,8.3.1 默认打印存在的不足,【例8.3】完善例8.2中的程序MyPrint,程序运行后,屏幕上能显示50个矩形。,129,8.3.2 实现多页打印功能,如果要使程序支持多页

44、打印功能,首先在打印之前设置要打印的页数,然后设置每一页视图原点的打印坐标。 1设置要打印的页数 一般在OnBeginPrinting()函数中设置要打印的页数,通过CPrintInfo类的SetMaxPage()和SetMinPage()函数实现。,130,【例8.4】完善例8.3中的程序MyPrint,设置要打印的页数,131,2设置正确的视图原点,为了正确打印每一页,需要设置每页打印的内容对应于坐标的那一部分区域。第一页视图原点的打印坐标为0,第二页视图原点的打印坐标下移一个页的高度,依此类推。 可以在OnPrepareDC()函数中通过调用CDC类成员函数SetViewPortOrg(

45、 )设置当前页的视图原点坐标。由于这些设置在OnPrint()和OnDraw()都起作用,既影响打印又影响显示器显示,因此必须调用CDC类的成员函数IsPrinting()来判断当前状态是打印输出还是显示器显示。,132,【例8.5】完善例8.4中的程序MyPrint,设置正确的视图原点。,133,8.4高级打印,8.4.1 页眉和页脚,完整的打印和打印预览程序包括控制页边距,设计页眉页脚、多页打印以及预览等功能。 页眉和页脚可以醒目地向用户提示一些重要的信息,如文章标题、页码等。,134,添加打印页眉、页脚的程序代码可以分两步进行: (1) 页眉和页脚将在打印纸上占用一定的空间,如果打印区域

46、太大,有可能和正文打印区域相重叠,被正文所覆盖。因此,应在OnPrint()函数中利用CPrintInfo*pInfo的成员变量m_rectDraw来设置打印页上打印区域的大小。 (2) 在m_rectDraw范围之外打印页眉和页脚。,135,8.4.2 设置页边距,页边距是指打印的文本区域与打印纸边界之间的距离,包括左、右、上和下边距。设置页边距时可参考CPrintInfo的成员变量m_rectDraw的数值,但m_rectDraw的数值表示的是有效打印区域,它本身与打印纸边界有一定的边距,这个边距是打印机自身造成的,称之为物理边距,并且这些物理边距在不同大小的纸张中是不一样的,因此首先要调

47、用全局函数GetDeviceCaps获取这些数值。,136,【例8.6】编写一个多文档的应用程序MyPage,设置页眉和页脚,在页眉处输出标题,在页脚处输出页码。,137,第 9 章 动态链接库 9.1 概述 9.2 创建MFC DLL 9.3 使用MFC DLL 9.4 MFC扩展 DLL,Visual C+程序设计与应用教程,138,在多任务环境中,为了提高系统资源的利用率和系统的整体性能,应该使每一个应用程序尽量少占用系统内存等资源。 动态链接库便是这一设想的体现,允许多个应用程序同时共享动态链接库在内存中的同一份拷贝。,9.1 概述,139,9.1.1 动态链接库的概念,动态链接库(D

48、LL):是一种用来为其它可执行文件(包括EXE文件和其它DLL)提供共享的函数库。 DLL中一般定义有两种类型的函数:导出函数和内部函数。导出函数是可以被外部程序调用的函数,内部函数只能在DLL内部使用。,140,9.1.2 动态链接库和静态链接库的区别,动态链接库和静态链接库的主要区别是与应用程序的链接方式不同,前者进行的是动态链接,后者进行的是静态链接。,141,9.1.3 使用动态链接库的优点,(1) 实现多个应用程序共享数据和代码的方式。 (2) 提高应用程序的执行效率和运行速度。 (3) 方便应用程序的升级和售后支持。 (4)把应用程序所使用的资源,如图标、位图、字符串和对话框等,独

49、立出来做成DLL,为多个应用程序所共享。 (5) 动态链接库便于建立多语言的应用程序。,142,9.1.4 DLL文件的存放位置,程序所需的DLL文件必须位于下面4个目录之一中: (1) 当前目录 (2) Windows的系统的目录,如Windowssystem (3) Windows所在的目录,如WINNT (4) 环境变量PATH中所指定的目录,143,Visual C+ 6.0支持多种DLL,包括: 非MFC DLL 一般来说,非MFC DLL的内部不使用MFC,非MFC DLL的导出函数都使用标准的C接口,因此无论应用程序是否使用了MFC,都可以调用非MFC DLL。,9.1.5 动态

50、链接库的分类,144,MFC常规DLL MFC常规DLL实际上包含有两方面的含义。一方面它是“MFC的”,这意味着可以在这种DLL的内部使用MFC,另一方面它是“常规的”,这意味着它不同于MFC扩展DLL,在MFC规则DLL的内部虽然可以使用MFC,但是它与应用程序的接口不能是MFC,而是C函数或者C+类。因此MFC的常规DLL可以被非MFC或MFC编写的应用程序所调用。,145,MFC扩展DLL MFC扩展DLL一般用来提供派生于MFC的可重用的类,以扩展已有的MFC类库的功能。MFC扩展DLL使用MFC的动态链接版本。只有使用MFC生成的可执行程序(无论是EXE还是DLL)才能访问MFC扩

51、展DLL。,146,利用MFC AppWizarddll向导可以创建MFC DLL。 DLL文件与可执行文件非常相似,不同点在于DLL包含有导出表。导出表包含DLL中每个导出函数的名字,这些函数是进入DLL的入口点。只有导出表中的函数可以被外部程序调用。 从MFC DLL中导出函数常用以下两种方法:使用模块定义文件(.DEF)和使用关键字_declspec(dllexport)。,9.2 创建MFC DLL,147,9.2.1 使用.DEF文件,DEF文件是一个包含EXE文件或DLL文件声明的文本文件。每个.DEF文件至少必须包含LIBRARY语句和EXPORTS 语句,其他语句可以省。 DE

52、F文件常用的模块语句如下: 第一个语句必须是LIBRARY语句,这个语句指出DLL的名字,链接器将这个名字放到DLL导入库中,DLL导入库包含了指向外部DLL的函数索引指针。,148,EXPORTS 语句列出被导出函数的名字, 以及导出函数的数值(由号与数字构成)。序数值可以省略,编译器会为每个导出函数指定一个,但这样指定的值不如自己指定的明确。 使用DESCRIPTION语句描述DLL的用途,这个语句可以省略。 使用“;”开头的注释语句。,使用AppWizard创建一个MFC DLL时,AppWizard将创建一个.DEF文件的框架,并自动添加到项目中。建立DLL时,链接器使用.DEF文件来

53、创建一个导出文件(.EXP)和一个导入库文件(.LIB),然后使用导出文件来创建.DLL文件。,149,【例9.1】 创建一个计算正方形和圆的面积的MFC 常规DLL的动态连接库Regulardll。,150,9.2.2 使用关键字_declspec(dllexport),从MFC DLL中导出函数的另一种方法是在定义函数时使用关键字_declspec(dllexport)。这种情况下,不需要.DEF文件。导出函数的形式为: declspec(dllexport) ();,151,【例9.2】 修改例9.1创建的动态连接库Regulardll,使用关键字_declspec(dllexport)

54、 导出函数。,152,【例9.3】创建一个MFC 常规DLL的动态链接库Areadll,在该动态链接库中添加一个导出类CArea,通过该类获取正方形和圆的面积。,153,如果需要使用导出顺序值,那么应该使用DEF文件来导出函数。 使用DEF文件来导出函数,可以创建具有NONAME属性的DLL。 使用declspec(dllexport)关键字导出函数不需要编写DEF文件,因此,如果编写的DLL只供自己使用,使用_declspec(dllexport)较为简单。,9.2.3 两种导出函数方法的比较,154,9.3 使用MFC DLL,应用程序与DLL链接后,DLL才能通过应用程序调用运行。应用程

55、序与DLL链接的方式主要有如下两种:隐式链接和显式链接。 隐式链接又称为静态加载,指的是使用DLL的应用程序先链接到编译DLL时生成的导入库LIB文件,执行应用程序的同时系统也加载所需的DLL。 显式链接又称为动态加载,使用显式链接DLL的应用程序必须在代码中动态地加载所使用的DLL,并使用指针调用DLL中的导出函数,在使用完毕后,应用程序必须卸载所使用的DLL。,155,9.3.1 使用隐式链接,使用隐式链接除了需要相应的DLL文件外,还必须具备以下3个文件: 包含导出函数以及类声明的头文件 DLL的导入库LIB文件 实际的DLL文件,156,编译时将DLL的LIB文件加入应用程序中,主要有

56、如下3种方法。 在主菜单project中,选择菜单项【Add To Project| Files】菜单项,在弹出的 Insert Files Into Project对话框中选择所需的LIB文件。 在程序的StdAfx.h头文件中加入下列语句: #pragma comment (lib,指定的LIB文件名) 在主菜单project中,选择【Settings】菜单项,弹出Project Settings对话框,如下图所示。选择Link标签页,在Object/library modules文本框中输入指定的LIB文件名,多个库文件之间用空格分开。,157,158,【例9.4】创建一个单文档的应用程

57、序ImLink,隐式链接例9.1创建的Regulardll.dll,使用其中的导出函数求正方形的面积。执行【链接DLL | 链接Regulardll】菜单命令,输入数据后,运行效果如图所示。,159,【例9.5】修改例9.4创建的单文档应用程序ImLink,隐式链接例9.2创建的Regulardll.dll,使用其中的导出函数求正方形的面积。,160,【例9.6】 在例9.5创建的单文档应用程序ImLink中,增加一个菜单项,隐式链接例9.3创建的Areadll.dll,使用其中的导出类求圆的面积。,161,9.3.2 使用显式链接,使用显式链接时,需要知道导出函数返回值的类型和所传递的参数个

58、数、类型和顺序等。应用程序在调用DLL中的导出函数前,必须首先调用LoadLibrary()函数加载DLL并得到一个模块句柄,然后使用得到的模块句柄调用GetProcAddress()函数获取导出函数的指针,并使用该指针调用DLL中的导出函数。DLL使用完毕后,调用FreeLibrary()函数释放加载的DLL。 若DLL是MFC扩展DLL,则应用程序应该分别使用AfxLoadLibrary()和AfxFreeLibrary()函数来加载和释放DLL。,162,【例9.7】创建一个单文档的应用程序ExLink,显式链接例9.1创建的Regulardll.dll。,163,9.4 MFC扩展 D

59、LL,MFC扩展DLL的含义在于它是MFC的扩展,其主要功能是实现从现有MFC类库中派生出可重用的类。,164,9.4.1 创建MFC扩展 DLL,对于MFC扩展DLL,系统会自动在项目中添加如下表所示的宏,这些宏为DLL和应用程序的编写提供了方便。,165,【例9.8】创建一个MFC扩展DLL的动态连接库Extensiondll,在这个DLL中导出一个对话框类,这个对话框类派生自CDialog。,166,9.4.2 使用MFC扩展 DLL,【例9.9】 在例9.6创建的单文档应用程序ImLink中,再增加一个菜单项,隐式链接例9.8创建的Extensiondll.dll。,167,第 10 章 多线程编程,Visual C+程序设计与应用教程,10.1 概述 10.2 线程

温馨提示

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

评论

0/150

提交评论