《VISUALC++MFC扩展编程实例1.pdf》由会员分享,可在线阅读,更多相关《VISUALC++MFC扩展编程实例1.pdf(20页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、下载无论读者是否已经读过本系列的书籍,或者已经具备了多年的编程经验,我们仍将在这一部分回顾一下所需要的基本知识,其目的就在于能够使读者更好地理解本书的实例。编写程序常常是一种需要尝试不同方法以达到最终目的的工作。通常情况下,了解用 M F C来做什么涉及到对4个基本概念的理解:Windows API怎样创建窗口;M F C如何封装并改进Wi n d o w sA P I;M F C如何与窗口通信以及 M F C是怎样控制绘图任务的。除了这些概念以外,本部分还将讨论一下工具栏和状态栏。最后我们将讨论一下 M F C如何同非Wi n d o w s构件进行通信,如串行口和I n t e r n e
2、 t站点。本部分包括的章节介绍如下。第1章概述本章概述M F C如何封装并改进Windows API。如果读者已经阅读过本系列书籍的前一本,将会发现该章是对那些版本基础部分的一些回顾。本书包含这一章是为了保持本书对高层次读者的独立性。第2章控件条本章将讨论M F C支持的控件条。标准的控件条包括工具栏、状态栏和伸缩条(R e b a r)等。M F C增加了对话条和停靠栏。该章还要探讨 M F C如何避免控件条之间以及它们和视之间互相覆盖的技术内幕。第3章通信本章讨论应用程序与外部世界的不同通信方式。其中最基础的窗口消息将在第一章中讨论。本章还涉及其他一些通信途径,包括局域网、I n t e
3、r n e t通信、串行和并行端口、D D E、Wi n d o w s挂钩和管道等。第 1 章 概述本章将回顾Wi n d o w s应用程序的基本知识,包括应用程序如何创建窗口、窗口之间如何进行对话以及如何在窗口内绘图。然后将讨论微软基础类库(M F C)以及Developer Studio怎样使创建窗口应用程序的工作变得容易起来。1.1 Windows基础当Wi n d o w s操作系统启动应用程序时,它首先创建一个程序线程,该线程一般只是一个第一部分基础可执行内存的管理模块,而这些内存则与系统中其他应用程序分享执行时间。如果这个应用程序要通过显示屏幕与用户交互,那么这个程序线程便需要
4、负责创建显示在屏幕上的窗口。程序线程通过调用操作系统的应用程序编程接口(A P I)来创建这些窗口。实际调用的函数是:C r e a t e Wi n d o w E x(),这个函数需要下列参数:屏幕位置、窗口大小以及即将创建的窗口的风格。1.1.1 窗口类结构线程创建的多数窗口具有类似的风格(例如按钮),这些类似的风格已经被集成为一个名为窗口类(Windows Class)的结构。注意这是一个结构,而不是一个 C+类。在创建窗口时必须设定窗口类。也可以使用其他的窗口风格,并且分别设定各自的窗口类结构。1.1.2 消息如果用户单击了一个窗口,操作系统就会向这个窗口发送一个消息来把这一事件通知
5、给它。每个窗口用自己的窗口处理过程来处理窗口消息,举个例子,一个按钮的窗口处理过程可能向它的主窗口发送一个消息告诉它需要做什么事情。每个窗口的处理过程还负责在屏幕上绘制属于自己的窗口。操作系统在绘制窗口时会向目标窗口发送W M _ PA I N T消息。所有类似的窗口具备同样的窗口处理过程,例如,所有的按钮控件使用同样的窗口处理过程,因此所有的按钮看起来外表都很类似,其行为也类似。这种情况下的窗口处理过程位于操作系统内。它的地址在窗口的窗口类结构内指定。所有的按钮控件都由同样的窗口类创建,这个窗口类结构的名字叫做B U T TO N。1.1.3 客户区和非客户区窗口处理过程在屏幕上绘制一个窗口
6、时实际上绘制了两个部分:客户区和非客户区。为了绘制非客户区(nonclient area),窗口处理过程总是调用所有窗口过程都需要调用的相同的操作系统处理过程。该过程接下来还需要绘制框架、菜单条以及标题栏等等多数窗口共同具有的内容。过程所绘制的东西取决于窗口的风格。例如,由于按钮的风格被指定为不用绘制其非客户区,所以按钮窗口上就不会看见框架和菜单。窗口的客户区(client area)总是由窗口自己的窗口处理过程绘制,也可能由操作系统来完成这件事,例如所有的按钮都由同样的处理过程来绘制,或者由创建者自己来绘制图像或列表。1.1.4 重叠窗口、弹出窗口和子窗口除了窗口类以外,还有成百上千种窗口风
7、格供用户指定窗口的绘制及其行为。其中有 3种最重要的风格创建了对应3种最基本的窗口类型:重叠窗口、弹出窗口和子窗口。重叠窗口(overlapped window),具有应用程序主窗口的全部特点。它的非客户区包括一个可伸缩的框架、菜单条、标题栏和最小化、最大化按钮。弹出窗口(popup window),具有消息框或者对话框的全部特点。它的非客户区包括一个固定大小的框架和一个标题栏。2第第第一部分第基础下载子窗口(child window),具有类似按钮控件的全部特点。它没有非客户区,窗口的处理过程负责绘制窗口的每个部分。这些窗口在其行为上表现不同,这将在以后讨论。1.1.5 父窗口和宿主窗口由于
8、用户界面可能会由好多个窗口组成,所以由程序线程控制它们将是很困难的,例如,如果用户将一个应用程序最小化,那么程序线程应该对那些组成用户界面的所有最小化窗口负责吗?实际上并没有采取直接控制的方式,应用程序创建的每个窗口都通过调用:C r e a t e Wi n d o w E x()分配了一个控制窗口。如果这个控制窗口被最小化,那么所有被其控制的窗口都会由操作系统自动地最小化。如果控制窗口被销毁,那么每个被控制窗口也随之被销毁。每个被控窗口也可以作为其他窗口的控制窗口,结果最小化或者销毁某些窗口都只影响用户界面的一部分。无论是什么窗口或者位于何处,程序员都可以在它内部创建另外的窗口。子窗口的控
9、制窗口叫做父窗口(parent window)。父窗口剪切其子窗口,也就是子窗口不能在其父窗口以外绘制。当用户与类似按钮的子窗口交互的时候,这些子窗口将自动地生成消息并发送到其父窗口。这就使得控件可以在父窗口的窗口处理过程中被集中处理。图1-1 构成一个Windows应用程序界面的窗口弹出窗口和重叠窗口的控制窗口叫做宿主窗口(owner window)。与父窗口不同,宿主窗口并不限制属于它的窗口。然而,当最小化宿主窗口的时候,它的所属窗口也将被最小化。但是,当宿主窗口隐藏的时候,它的所属窗口却仍然显示。请参见图 1-1以了解组成Wi n d o w s应用程序的各种窗口。1.2 Windows
10、消息上面提到,每个窗口由其自己的窗口处理过程响应来自操作系统或者其他窗口的消息。例如,用户用鼠标单击了某个窗口,那么操作系统可能就会向这个窗口发送一个消息。如果这是一个标识为Load File的按钮窗口,那么它的窗口处理过程就可能向应用的主窗口发送一个消息通知加载文件。主窗口处理过程将加载文件并在其客户区显示文件内容来作为响应。接下来讨论消息是如何传送的。第 1 章第概第第述第第3下载一个重叠窗口。宿主窗口是桌面,也叫主窗口子窗口。文窗口是主窗口弹出窗口。宿主窗口是主窗口子窗口。文窗口是它所在的弹出窗口1.2.1 发送或寄送消息传送消息到窗口有两种方式:发送(s e n d)或者寄送(p o
11、s t)。这两种方式之间的主要差别在于被寄送的消息不必立即处理。被寄送的消息放置于一个先入先出的队列里等待应用程序空闲的时候处理,而被发送的消息需要立即处理。实际上,发送消息到窗口处理过程和直接调用窗口处理过程两者之间几乎没有任何不同。只是,你可以要求操作系统截获所有为达到某个目的而在应用程序中被发送的消息,但不能截获对窗口处理过程的直接调用。与用户输入相对应的消息(如鼠标单击和按下一个按键)通常都是以寄送的方式传送,以便于这些用户输入可以由运行较缓慢的系统进行缓冲处理。而其余的所有消息都是被发送的。在以上的例子中,系统寄送了鼠标单击消息,而按钮窗口则向其主窗口发送了 Load File消息。
12、1.2.2 消息类型有3种类型的消息:窗口消息、命令消息和控件通知消息:窗口消息(Window message)是由操作系统和控制其他窗口的窗口所使用的消息。这一类的消息有C r e a t e、D e s t r o y和M o v e等等。上例中的鼠标单击消息也是一种窗口消息。命令消息(Command message)是一种特殊的窗口消息,它从一个窗口发送到另一个窗口以处理来自用户的请求。在以上例子中,从按钮窗口发送到主窗口的消息就是命令消息。控件通知消息(control notification)是最后一种消息类型。它类似命令消息,当用户与控件窗口交互时,这一类消息就从控件窗口发送到其主
13、窗口。但是,这种消息的目的并不在于处理用户命令,而是为了让主窗口能够改变控件,如加载并显示更多的数据。以上所述的例子中并没有控件通知消息,但是,假如按钮发送了鼠标单击消息给它的主窗口,那么这个消息也可以看作是一个控件通知消息。一个普通的鼠标单击消息可以由主窗口直接处理,然后由控件窗口处理。1.2.3 接收消息窗口处理过程看起来与其他函数和方法没有任何不同。消息到来后,按照消息类型排序进行处理。其中的参数则由调用函数提供以进一步区分消息。命令消息由 w P a r a m中的命令I D分类。D e f Wi n d o w P r o c()函数则发送任何程序员都不会去处理的消息给操作系统。所有
14、传送到窗口的消息都将通过这个函数,甚至包括绘制窗口非客户区的消息尽管最终它们都将绕过D e f Wi n d o w P r o c()函数。一个主窗口的处理过程实例如下:MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)switch(message)case WM_CREAT E:b r e a k;case WM_PA I N T:b r e a k;case WM_COMMAND:4第第第一部分第基础下载switch(id)case IDC_LOAD_FILE:b r e a k;b r e a k;d e f
15、a u l t:return(DefWindowProc(hWnd,message,wParam,lParam);return(NULL);1.2.4 窗口处理函数的子类化上面提到过,在窗口类中定义了窗口处理过程的地址。由窗口类所创建的窗口将把它们的消息传递给窗口处理过程。如果程序员使用的是一个由系统提供的窗口类,并要增加自己对窗口的特殊处理,就需要使用子类化(s w b o l a s s i n g)。将窗口指向自己的窗口处理过程,便对窗口进行了子类化,这样所有的消息都可以由程序员自己处理了。如果只想处理一个或者两个消息,只需简单地将剩余消息传递给初始的窗口处理过程即可。我们注意到,采用子
16、类化并没有修改原先的窗口类,而是直接对窗口对象进行了修改,这个对象保存了一份窗口处理过程地址的拷贝。与此相反,超类化(s u p e r c l a s s-i n g)则修改了原始的窗口类,然后将其应用于创建窗口,但由于可以更方便、安全地使用 M F C来获得由超类化带来的好处,所以这种方法就很少采用了。请参见图1-2了解子类化概念。1.3 窗口绘图Windows API为窗口绘图提供了好几种调用函数。它们是点、弧、图形和圆绘图函数以及图形填充和位图绘制等函数。正是因为采用了绘图 A P I,所以程序员必须负责传递坐标数值、颜色、宽度和绘图位置,而 A P I函数则负责剩余的工作。为了简化对
17、 Windows API的图像函数调用,一些参数被固化到了一个名为设备环境的可重用对象中。1.3.1 设备环境图像设备环境(Device Context)是一个简单的对象,它包含了对绘图而言比较共同的属性,第 1 章第概第第述第第5下载窗口对象指向创建它的窗口类的窗口过程通过设置自己的窗口过程地址来子类化该窗口任何不希望自行处理的消息可以交由初始窗口过程负责处理窗口对象初始窗口过程新窗口过程图1-2 窗口处理函数的子类化例如绘图位置、线宽、填充模式的颜色等等。这个对象可以一次设置然后多次重复使用。实际上并不需要自己创建设备环境,只要调用几个可能的 A P I函数,系统就可以返回已经被预先准备好
18、的设备环境值。例如,系统为屏幕创建的设备环境包含屏幕上将用于绘图的颜色以及绘图工具的当前位置,程序员则可以在该位置进行绘图并设置颜色。1.3.2 绘图工具设备环境并没有包括绘图所需的全部特征。有几个特征存在于设备环境可以引用的附加图像对象中。这些对象都各自代表了某一特定绘图工具的特征(如:画笔的色彩和宽度、画刷采用的模式等)。这些工具包括绘制直线的画笔;用某种模式填充封闭区域的画刷;确定文本绘制效果的字体以及确定使用何种颜色的调色板等等。另外的两种绘图工具:位图和区域则显得更抽象一些。位图工具看起来像画刷,除了它只能用位图模式填充一个区域。而区域工具则类似于画笔工具,但它起的是剪切作用,例如可
19、以使用区域工具从一个位图中将“S TO P”单词分割出来。1.3.3 映射模式设备环境保持跟踪程序员采用的映射模式。设置映射模式可以指定调用参数中以英寸或者厘米作为度量单位的坐标 x和y,每个绘图函数则可以自动确定绘制多少像素。可用的映射模式如下表所示。表1-1 可用的映射模式模式使 用 说 明M M _ T E X T这是缺省的映射模式,坐标值x和y精确地等于一个屏幕像素或者一个打印机的打印点,y的正方向沿屏幕或者打印页向下M M _ H I E N G L I S Hx和y值为屏幕或者打印页上一英寸的 1/1 0 0 0。窗口决定当前屏幕设备应该有多少个像素等于1/1 0 0 0英寸。Y的
20、方向则为沿屏幕或者打印页向上M M _ L O E N G L I S Hx和y值为设备上一英寸的1/1 0 0 0,y向上为正M M _ H I M E T R I Cx和y值为设备上一毫米的1/1 0 0,y向上为正M M _ L O M E T R I Cx和y值为设备上一毫米的1/1 0,y向上为正M M _ T W I P Sx和y值为设备上一英寸的1/1 4 4 0,y向上为正。这个模式通常应用于绘制文本,一 t w i p等于一个字体点的1/2 0M M _ A N I S O T R O P I C程序员通过设置接下来将讨论的窗口和视口以决定 x和y代表多少像素M M _ I
21、S O T R O P I C同上,但x和y代表的像素数必须相等1.3.4 窗口视和视口视M M _ A N I S O T R O P I C和M M _ I S O T R O P I C映射模式允许程序员自定义将坐标 x和y换算为像素数的转换比率。这个工作由定义两种叫做视的矩形来完成。首先应该定义一个代表将要绘制的整个区域(例如:0,0,1 0 0 0,1 0 0 0)的矩形,然后定义一个代表那些最终出现绘图结果的屏幕或打印机上的对等坐标(例如:0,0,5 0 0,5 0 0)的矩形。第一个矩形叫做窗口视6第第第一部分第基础下载(Window Vi e w),第二个矩形叫做视口视(Vie
22、wport Vi e w)。如果在设备环境中定义了这两个矩形,并使用上述两种映射模式之一,那么使用窗口视坐标的图形将自动地被转换为使用视口视的坐标。除了视口视的坐标之外,程序员可以缩小、放大以及颠倒自己的图形,而不需要改变其他任何东西。1.3.5 逻辑单位和设备单位使用除M M _ T E X T以外的绘图模式绘图的时候,传递给绘图函数的坐标采用逻辑单位(Logical Unit)。逻辑单位可以是英寸、厘米或者像素。绘图函数本身则用设备单位绘图。举一个例子,直线绘图函数可能使用 2 5 4个像素代表一个1英寸的逻辑单位,这里的数字 1就是逻辑单位数值,而数字2 5 4则是设备单位(Device
23、 Unit)数值。这并不会成为一个问题,除非打算让用户能够使用鼠标绘图。鼠标传回给应用程序的任何坐标都是以设备单位计量的数值,因此必须使用一些Windows API将这些坐标值转换为逻辑单位数值。1.3.6 绘图函数Windows API具有多个绘图函数,举例如下:画点函数:如S e t P i x e l()。画线函数:如L i n e To()、A r c()、P o l y l i n e()。画图形函数:如R e c t a n g l e()、P o l y g o n()、E l l i p s e()。填充和图形反转函数:如F i l l R e c t()、I n v e r
24、t R e c t()、F i l l R g n()。滚屏函数:S c r o l l D C()。文本绘制函数:如Te x t O u t()、D r a w Te x t()。位图和图标绘制函数:如D r a w I c o n()、B i t B l t()。1.3.7 抖动和非抖动颜色所有可用的绘图函数,包括从画线到画图形和文本,都需要使用颜色。但是,除非系统具备足够的显示内存,否则颜色将必须利用抖动(D i t h e r e d)方式。所谓抖动颜色实际上是一些主要颜色的集合,在显示的时候通过几个颜色相互混合以获得某种理想的色彩。对大多数情况,抖动颜色已经足够了。然而,由于抖动颜色
25、显得比较模糊,对图像应用程序而言通常不足以达到要求。图像应用程序不希望线条与其包围的图形颜色相互渗透混合。对图像应用程序可以有以下几种选择方案:增加更多的显示内存。需要颜色抖动的理由在于,虽然屏幕上的每个像素都具有自己的R G B颜色。但一般的系统都没有足够的显示内存来为每个像素存储其R G B值。例如,设每个像素为 3 2位,那么一个 8 0 06 0 0像素的屏幕就需要 2 M字节的显示内存以容纳所有的颜色值。只用标准颜色绘图。Wi n d o w s使用的显示卡保证了至少能定义 2 0种标准颜色,因为它需要使用这些颜色来创建抖动效果。配置自己的颜色。除了标准颜色以外,显示卡还有一些空间可
26、定义 2 0 0多种颜色,可以在设备环境调色板内定义这些颜色并只用这些颜色绘图。多数图像应用都采用了这种方法,此方法将在实例3 1中得到详细描述。第 1 章第概第第述第第7下载1.3.8 设备无关位图每个像素都有自己的R G B颜色,每种颜色的数值范围可以为 02 5 4。一排同样颜色(例如黑色)的像素在屏幕上显示一条直线,一个具有不同颜色像素的矩形就可以创建任何图像。将这些像素的色彩数值存到一个文件中就得到了一个位图文件。这个文件的头不仅要指示文件包含了多少颜色值,而且还要指出多少颜色值组成一排。如果位图文件中的每个颜色值都包含完整的 R G B数值,那么,由于这个颜色值完全在位图中得到定义
27、,这个文件就是一个设备无关位图。如果每个颜色值实际上都是对某个颜色表的字节索引,那么,在它同时包含了这个颜色表的情况下,这个文件仍然是设备无关的。像这样的颜色索引常用于压缩位图的大小。一个 8位索引只占用3 2位R G B值空间的四分之一。设备无关位图(Device Independent Bitmaps)由对颜色表的索引组成,这个颜色表在系统的显卡中被定义。这就是在上节的第 3步为显示非抖动颜色而配置的颜色表,如果某个位图指向它的话,那么这个颜色表将不能独立于设备之外而存在。1.3.9 元文件除了在屏幕或者打印机上绘图,还可以在文件中绘图,这样的文件就是元文件(M e t a f i l e
28、)。元文件的优点在于:无论绘制的内容是什么,它们都将完整地重现。由于元文件可以伸展得到更好的效果,而位图进行伸展时会扭曲变形,所以元文件优于用位图的形式存储图像。1.3.10 何时绘图看起来这个话题可能有点傻,但对一个多任务操作系统而言,应用程序之间不得不争夺屏幕上有限的显示空间。哪怕只是在自己的窗口中绘图,也不可能想做什么就做什么。通常只是在窗口接收到 W M _ PA I N T消息或者W M _ D R AW I T E M消息(针对所属的控件窗口)的时候才绘图。系统仅在窗口被部分遮盖以及由于关闭其他窗口而显现出来的时候才发送这些消息。或者说,如果需要重画以显示新的信息,系统在这种情况之
29、下将发送这些消息。1.4 MFC基础到目前为止,我们只讨论了应用程序可以从 Windows API中所获得的功能。但A P I并不是面向对象的。例如,使用A P I不可能在创建一个窗口实例之后再调用其成员函数作用于该窗口。并且,不能从窗口类派生出一个可以加入自己所需功能的类,比方说,不可以增加自己的窗口处理过程。微软基础类库所要做的就是向应用程序提供可以访问 Windows API的一种模拟面向对象的访问方式。在功能上,每个 M F C类都紧密结合一种Wi n d o w s资源对象(如窗口),而A P I函数则控制该资源。举个例子,M F C的C W n d类创建并控制窗口。而操作系统一创建
30、窗口就会开辟一块叫做Wi n d o w对象的管理内存,然后返回该对象的指针,也就是窗口句柄。MFC CWnd类则以成员变量的形式存储这个句柄,并且由 C W n d的成员函数调用该变量来控制该窗口。例如,C W n d的M o v e Wi n d o w()成员函数调用Windows API:MoveWi n d o w()来移动属于该窗口句柄的窗口。因为M F C是用C+写成的,所以,程序员可以从C W n d类派生自己的类并在其中增加所需功能。8第第第一部分第基础下载但是,因为这只是面向对象设计的一个模拟,所以 M F C类对操作系统内部工作的控制能力并不会比任何其他A P I调用更多
31、。例如,如果对窗口打开方式的修改是 A P I的内部功能,那么即使使用M F C类来试图改变这一方式也是不可能的。创建和销毁M F C类创建M F C类是一个棘手的问题。对封装了类似窗口系统资源的 M F C类来说,程序员不仅要创建自己的M F C类的实例,还要调用该类的成员函数来创建该系统资源。因此 M F C类的创建几乎总是分成两步走:1)创建一个类的示例;2)创建系统资源。注意为什么M F C类不仅仅只是简单地在它们自己的构造函数内创建系统资源呢?这是因为,创建系统资源是否成功是不可能预先知道的,而类的构造函数又难于访问(它甚至不返回错误状态),利用成员函数来完成这一工作则要容易得多。销
32、毁M F C类也同样棘手。如果类的实例首先被销毁,那么它将简单地在其析构函数内销毁资源。然而,如果开始就没有资源,那么 Windows API也就没有办法知道有一个 MFC 类实例必须被销毁。令人惊奇的是,这只是存在于 C W n d类和窗口资源之间的问题,其他类型的资源并不由用户销毁。但是用户可能通过单击窗口的关闭按钮来关闭窗口,在这种情况下,不知何故,C W n d对象必须知道足够的信息来销毁自己以防止出现内存泄漏。幸运的是,当窗口资源被销毁时,它会发送一个消息,而C W n d对象可以捕获这个消息以用于销毁自身。因为M F C类对象和系统资源是两种不同实体,所以可以通过编程的方法将两者分
33、开或者重新组合在一起。例如,通过调用 A t t a c h()函数可以将一个C W n d类对象附着于一个已经存在的窗口对象上。所有控制系统资源的 M F C类都具有A t t a c h()函数和D e t a c h()函数。1.5 Developer Studio基础为了将 M F C类恰当地运用于应用程序,Developer Studio(开发平台)提供了几种向导(Wi z a r d)工具和编辑器工具:A p p Wizard 用于生成应用程序所需要的基本类文件。所产生的类都派生于 M F C类,它们在编译后与M F C库链接以创建应用程序。C l a s s Wizard 用于创
34、建应用程序额外的文件或者为已有的类增加新的成员函数。这些被创建的类可以由M F C派生。Dialog Editor 用于创建对话框模板,方法是将控件窗口图标拖到一个空白的框架窗口内。被创建的模板作为应用程序的资源存储,然后用于在运行时候创建对话框。C l a s s Wi z a r d可以直接从Dialog Editor调用以创建一个对话框类,该类则负责创建对话框。Toolbar Editor 用于创建工具栏和位图资源,而这些资源则又用于创建应用程序的工具栏。C u r s o r、I c o n和Bitmap Editor 是简单的图像编辑器,用于创建应用所使用的光标、图标和位图资源。Me
35、nu Editor用于创建应用中的菜单条和弹出菜单资源。String Editor用于创建字串资源,它可以将文本字符串从应用程序中分离出来,并且可以很方便地从一种语言转变为另一种语言(例如从英语转变为法语,而不是从 C+到J AVA)。第 1 章第概第第述第第9下载Text Editor用于编辑类文件。1.6 Windows和MFC总结以上所述说明了Wi n d o w s、M F C和Developer Studio是如何一起协同工作的。Wi n d o w s操作系统创建并支持应用程序,其中包括窗口的创建。M F C则在C+类中封装了这一功能,而Developer Studio则负责创建这
36、些类。现在来回顾一下M F C提供了哪些类。1.7 基本类多数M F C类由下列3种基本类派生:C O b j e c t、C C m d Ta rg e t和C W n d。如上所述,C W n d类封装了创建和控制窗口的 Windows API,它还允许程序员向窗口处理函数中添加自己的消息处理过程。C C m d Ta rg e t类则允许没有创建窗口的类也能处理消息,但只能是后面要讨论的所谓命令消息。C O b j e c t类为每个从它派生的类提供了许多基本功能,例如得到类对象的大小,将对象存入一个磁盘文件等等。1.CObject类CObject 类本身并没有提供什么重要的功能。该类通
37、过 6种相互配合的宏(m a c r o)完成实际工作。这些宏使得类在运行时可以从 C o b j e c t类派生以获得类的名字和对象大小。创建一个这样的类不必要知道类的名字,文档环境存储和接收这种类的实例也不必知道类的名字。下列宏允许类的实例知道它自己的类名字和运行时的类大小:DECLARE_DYNAMIC(CYourClass)/in the.h fileIMPLEMENT_DYNAMIC(CYourClass,CYo u r B a s e C l a s s)/in the.cpp file使用C O b j e c t:G e t R u n t i m e C l a s s()
38、函数可以在运行时使用这些宏来获得与类有关的细节。另外几个宏包括以上宏的功能,但同时允许类的实例在不知道它的类名字的情况下被创建:D E C L A R E _ D Y N C R E ATE(CYourClass)/in the.h fileI M P L E M E N T _ D Y N C R E ATE(CYourClass,CYourBaseClass)/in the.cpp file使用C O b j e c t:C r e a t e O b j e c t()函数可以利用这些宏创建一个类的实例而无需知道它的类名字。另外几个宏包括以上所有宏的功能,但同时允许类实例在不知道它的类名
39、字的情况下被存贮:DECLARE_SERIAL(CYourClass)/in the.h fileIMPLEMENT_SERIAL(CYourClass,CYourBaseClass,schema)/in the.cpp file 2.CCmdTa rg e t类从C C m d Ta rg e t类派生的类可以接收并处理由应用程序的菜单或者工具栏发出的命令消息。C C m d Ta rg e t类将在以后的消息机制部分详细讨论。3.CWnd类如上讨论,C W n d类的成员函数封装了负责创建和维护窗口的 Windows API。C W n d类派生于C C m d Ta rg e t类,因此
40、能够接收和处理命令消息。所有其他的控制窗口的MFC 类都由该类派生。10第第第一部分第基础下载注意 本章所使用的下列字母用于指出MFC类从以上的何种基类派生:O代表派生于C O b j e c t。O C代表派生于C O b j e c t和C C m d Ta rg e t。O C W代表派生于C O b j e c t、C C m d Ta rg e t和C W n d。1.8 应用类A p p Wi z a r d以下列4种M F C类为基础,为应用程序产生出一些派生类:1)CWinApp 也就是应用程序的应用类(Application Class),它负责初始化并运行应用程序,这就是以
41、上讨论的程序线程。2)CFrameWnd 也就是应用程序的框架类(Frame Class),它负责显示并跟踪用户命令以及显示应用程序的主窗口。3)CDocument 应用程序的文档类(Document Class),它负责加载和维护文档。文档可以是从草稿到网络设置的任何东西。4)CView 应用程序的视类(View Class),它负责为文档提供一个或者多个视。注意这里使用了应用类、框架类等术语,但本书所指的都是以上4种基类的派生类。这4种类中的哪些类将包括在应用程序中,取决于所创建应用程序的类型。对话框应用程序(Dialog Application),只是简单地拥有作为用户界面的对话框而没有
42、框架、文档或者视类。对话框应用程序仅利用了应用类 C Wi n A p p的派生类。对话框则用 M F C的C D i a l o g类创建,这个类将在以后讨论。单文档界面应用程序(SDI:Single Document Interface Application),可以一次加载并编辑一个文档,它使用以上提到的全部 4种基类。多文档界面应用程序(MDI:Multiple Document Interface Application),可以一次加载并编辑几个文档,它使用以上提到的全部 4种基类,此外还增加了两个 C F r a m e W n d的派生类:C M D I F r a m e W
43、n d和C M D I C h i l d W n d。1.8.1 文档视C D o c u m e n t和C Vi e w类的派生类负责文档视。M F C应用程序是面向文档的,这意味着应用程序负责加载、观察、编辑并存储文档,而文档则可能是文本文件、图形图像或者二进制配置文件。文档类的工作是将文档从磁盘加载到它的成员变量。然后创建一个或者多个视类以显示这些成员变量。文档类仅需为文档类对象创建多个视类对象就可以拥有多个视。因为文档类没有关联的窗口,所以它并不是从 C W n d类派生的,而是从 C C m d Ta rg e t派生的,因而可以处理命令消息。1.8.2 CWinApp(OC)应
44、用类是应用程序运行时创建的第一个对象,并在应用程序执行的过程中最后一个终止。启动后,应用类就负责创建应用程序的其他对象。针对对话框应用程序,应用类用C D i a l o g创建一个对话框。针对S D I应用程序,应用类创建一个或者多个文档模板(参阅以后内容),然后使用该模第 1 章第概第第述第第11下载板打开一个空文档。针对M D I应用程序,应用类创建一个或者多个文档模板,然后使用该模板在主框架类内打开一个空文档。应用类派生于C Wi n A p p并从A p p Wi z a r d中得到类似C X x x A p p的类名字,X x x就是具体应用的名字。1.8.3 文档模板文档模板定
45、义了在应用程序打开一个文档时框架类、文档类和视类的创建结果。为了生成一个文档模板,必须为SDI 应用程序创建一个C S i n g l e D o c Te m p l a t e类或者为M D I应用程序创建一个C M u l t i D o c Te m p l a t e类,并用3个类指针对其初始化:p D o c Template=new CMultiDocTe m p l a t e(I D R _ A P P T Y P E,RUNTIME_CLASS(CAppDoc),/Your Document ClassRUNTIME_CLASS(CChildFrame),/Your Fra
46、me ClassRUNTIME_CLASS(CAppView)/Your View Class);其中的 R U N T I M E _ C L A S S()宏返回一个指向类的C R u n t i m e C l a s s结构的指针,D E C L A R E _ D Y N C R E AT E和I M P L E M E N T _ D Y N C R E ATE 宏则将该结构添加到类中。文档模板通过创建以上3个类的实例并调用其C R u n t i m e C l a s s:C r e a t e O b j e c t()函数打开文档。1.8.4 线程C Wi n A p p类
47、本身从C w i n T h r e a d类派生。而C Wi n T h r e a d类则封装了创建和维护系统中具体应用程序线程的Windows API。实际上,可以通过创建 C Wi n T h r e a d类的另一个实例以在应用程序中实现多任务。读者可以参考实例 5 6和实例5 7。C Wi n A p p类代表了应用程序中的执行主线程。1.8.5 CFrameWnd(OCW)框架类是应用程序运行时创建的下一个对象,它负责显示并为应用程序引导用户命令。对于S D I应用程序,框架类派生于 C F r a m e W n d类,A p p Wi z a r d将自动为它分配一个名字:C
48、 M a i n F r a m e。对于 M D I应用程序,框架类则派生于 C M D I F r a m e W n d类,A p p Wi z a r d也为它分配C M a i n F r a m e这个名字。同时 M D I应用程序还为每个打开的文档创建一个子框架类(C h i l dFrame Class)。每个子框架类都派生于C M D I C h i l d W n d,A p p Wi z a r d自动为子框架类分配名字:C C h i l d F r m。对话框应用程序没有框架类,正如上面提到的,对话框应用程序由应用类和对话框类组成。1.8.6 CDocument(OC
49、)文档类通常是应用程序创建的下一个类,应用程序或者打开一个新文档,或者打开一个已经存在的文档。文档类负责将文档加载到其成员变量中,并允许视类编辑这些成员变量。文档可以包括从图像文件到可编程控制器设置等任何内容。12第第第一部分第基础下载文档类派生于C D o c u m e n t类,A p p Wi z a r d自动为其分配的名字为C X x x D o c,其中X x x是应用程序的名字。1.8.7 CView(OCW)文档类的实例创建之后,紧接着就会创建一个视类的实例。视类负责描述文档类的内容。视类还允许用户编辑文档。分离窗口类 C S p l i t t e r W n d则允许文档
50、同时具有一个以上的视,这些视可以由好几个同样的或者不一样的视类创建。A p p Wi z a r d允许程序员从下列几个基类派生自己的视类,它们是:C Tr e e Vi e w、C E d i t Vi e w、C R i c h E d i t Vi e w和C L i s t Vi e w等等。每一种基类给予应用程序一组不同功能。所有这些类都从 C Vi e w类派生。无论选择什么基类,A p p Wi z a r d自动为派生类分配的名字为C X x x Vi e w,其中X x x是应用的名字。如上所述,可以从这4种基类创建3种类型的M F C应用程序:对话框、S D I和M D I