当前位置:首页 >> 小学教育 >>

第4章 创建应用程序框架2


本章内容
?
? ? ? ?

应用程序框架
应用程序向导 应用程序向导生成的文件 ClassWizard类向导 程序调试

通过本章的学习我们可以真 正利用Visual C++创建一个 简单的 MFC 应用程序。

何谓应用程序框架?
同一类型应用程序的结构大致相同,并有很多

相同的源代 码 , 因 此 可 以 通 过 一 个 应 用 程 序 框 架 AFX(Application FrameWorks)编写同一类型应用程序的通用源代码。

4.1 应用程序向导
? ?

?

与其它可视化开发工具一样,Visual C++提供了创建应用程序 框架的向导AppWizard和相关的开发工具。 在可视化开发环境下,生成一个应用程序要做的工作主要包 括编写源代码、添加资源和设置编译方式。向导实质上是一 个源代码生成器,利用应用程序向导可以快速创建各种风格 的应用程序框架,自动生成程序通用的源代码,这样大大减 轻了手工编写代码的工作量。 即使不熟悉Visual C++编程,也可以利用它的应用程序向导一 个简单的应用程序。

4.1.1 Visual C++向导的类型
创建一个应用程序,首先要创建一个项目。项目用于管理组成应 用程序的所有元素,并由它生成应用程序。 Visual C++集成开发环境包含了创建各种类型应用程序的向导, 执行File菜单中的New命令即可看到向导类型。 Visual C++集成开发环境中主要向导类型:
? ? ? ? ? ?

?
? ?

Datebase Project:创建数据库项目 MFC ActiveX Control Wizard:创建基于MFC的ActiveX控件 MFC AppWizard[dll]:创建基于MFC的动态链接库 MFC AppWizard[exe]:创建基于MFC的应用程序(最常用) New Database Wizard:在SQL服务器上创建一个SQL Server数据库 Win32 Application:创建Win32应用程序,可不使用MFC,采用API方法 编程 Win32 Console Application:创建DOS下的Win32控制台应用程序,采用 C++或C语言进行编程 Win32 Dynamic-link Library:创建Win32动态链接库,采用API方法 Win32 Static Library:创建Win32静态链接库,采用API方法

4.1.2 MFC AppWizard的使用步骤
引入应用程序向导的目的:
区别于DOS程序,即使一个简单的Windows程序,它也必 须显示一个程序运行窗口,需要编写复杂的程序代码。而同一 类型应用程序的框架窗口风格是相同的,如相同的菜单栏、工 具栏、状态栏和用户区。并且,基本菜单命令的功能也是一样

的,如相同的文件操作和编辑命令。所以,同一类型应用程序
建立框架窗口的基本代码都是一样的,尽管有些参数不尽相同。 为了避免程序员重复编写这些代码,一般的可视化软件开发工

具都提供了创建Windows应用程序框架的向导。

例4_1:编写一个单文档应用程序Mysdi,程序运行后在程序视图 窗口显示信息“这是一个单文档程序!”。

? ?

在Visual C++ 中执行File|New命令,出现New对话框。 确认New对话框的当前页面为Project,在左栏的项目类型列表框 中选择MFC AppWizard[exe]项,在Project Name框输入要创建项 目的名称。在Location栏中输入项目所在的目录,可单击右侧“…” 浏览按钮来对默认的目录进行修改。向导将在该目录下存放项目 的所有文件。单击OK按钮出现MFC AppWizard-Step1对话框。

在MFC AppWizard-Step1对话框中选择应用程序的类型。
?

Single document:单文档界面应用程序,程序运行后出现标准的 Windows界面,它由框架(包括菜单栏、工具栏和状态栏)和用 户区组成。并且程序运行后一次只能打开一个文档,如Windows 自带的记事本Notepad。

?
?

Multiple documents:多文档界面应用程序,程序运行后出现标 准的Windows界面,并且可以同时打开多个文档,如Word。
Dialog based:基于对话框的应用程序,程序运行后首先出现一 个对话框界面,如计算器Calculator。

在MFC AppWizard-Step 2 of 6选择应用程序所支持的数据库方式:
? ?

None:向导创建的应用程序不包括对数据库的操作功能,但以后可 以手工添加对数据库的操作代码(默认项)。 Header files only: 提 供 了 最 简 单 的 数 据 库 支 持 , 仅 在 项 目 的 stdAfx.h文件中使用#include指令包含afxdb.h和afxdao.h两个用于定 义数据库类的头文件,但并不生成与数据库相关的类,用户需要时 可以自己生成。 Database view without file support:包含了所有的数据库头文件, 并生成了相关的数据库类和视图类,但不支持文档的序列化,向导 创建的应用程序的File主菜单中将不包含有关文件操作的菜单命令 项。 Database view with file support:包含了所有的数据库头文件,生 成了相关的数据库类和视图类,支持文档的序列化。

?

?

在MFC AppWizard-Step 3 of 6选择应用程序所支持的复合文档类型:
? ? ?

None:应用程序不支持任何复合文档(默认项)。

Container:应用程序作为复合文档容器,能容纳所嵌入或链接的 复合文档对象。
Mini-server:微型复合文档服务器,应用程序可以创建和管理复 合文档对象,但对于它所创建的复合文档对象,集成应用程序可 以嵌入,但不能链接。微型服务器不能作为一个单独的程序运行, 而只能由集成应用程序来启动。 Full-server:完全复合文档服务器,除了具备上面微型服务器的功 能外,应用程序支持链接式对象,并可作为一个单独的程序运行。 Both container and server:应用程序既可作为一个复合文档容器, 又可作为一个可单独运行的复合文档服务器。

? ?

在MFC AppWizard-Step 4 of 6设置应用程序界面特征:
?
? ? ? ? ? ? ? ? ? ?

Docking toolbar:应用程序具有标准的工具栏(默认项)
Initial status bar:应用程序具有标准的状态栏(默认项) Printing and print preview:应用程序支持打印和打印预览功能 (默认项) Context-sensitive Help:应用程序具有上下文相关帮助功能 3D controls:应用程序界面具有三维外观(默认项) MAPI:应用程序具有发送电子邮件的功能 Windows Sockets:应用程序能使用套接字,支持TCP/IP协议 Normal:应用程序采用传统风格的工具栏(默认项) Internet Explorer ReBars:应用程序采用IE风格的工具栏 How many files would you like on your recent file list:在File主菜单 可列出文档的最多个数 Advanced按钮:进行更高一级的设置,如修改文件名或扩展名, 调整程序用户界面窗口的样式

在MFC AppWizard-Step 5 of 6设置项目的风格:
? ? ? ?

MFC Standard:应用程序采用MFC标准风格(默认项) Windows Explorer:应用程序采用Windows资源管理器风格 选择向导是否为源代码生成注释 设置MFC库与应用程序的链接方式: (1) As a shared DLL:采用共享动态链接库的方式(默认项) ,即 在程序运行时才调用MFC库。采用此方式可减少应用程序的代码 长度。 (2) As a statically linked library:采用静态链接库的方式,即在 编译时把MFC库与应用程序相链接。采用此方式能提高运行速度, 且不用考虑程序最终运行环境中是否安装了MFC库。

在MFC AppWizard-Step 6 of 6,列出了向导将创建的类,用户可 以修改一些类默认的类名和对应的头文件名、实现文件名。对某些类 还可以选择不同的基类。
在New Project Information对话框,根据用户在前面各步所做的 选择列出将要创建的应用程序的有关信息,如应用程序的类型、创建 的类和文件名、应用程序的特征以及项目所在的目录。若要修改这些 内容,可单击Cancel按钮返回到前一个对话框。单击OK按钮,MFC AppWizard[exe]向导将开始创建应用程序框架。 当应用程序框架创建成功后,Developer Studio将装入应用程序项 目,并在项目工作区窗口打开这个项目。值得说明的是,若想在同一 个目录下重新创建一个同名的项目,必须首先将原来的项目删除或移 走。 利用MFC AppWizard[exe]向导创建应用程序Mysdi的框架后,用 户无需添加任何代码,就可以对程序进行编译、链接,生成一个应用 程序。但一般情况下,用户应根据程序具体功能需要,利用Developer Studio中的集成工具向应用程序框架添加具体的代码。

在视图类的成员函数OnDraw()中实现屏幕输出 void CMysdiView::OnDraw(CDC* pDC) { CMysdiDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here pDC->TextOut(100, 100, “这是一个单文档程序!”); // 在坐标(100, 100)处显示文本串

}
执行Build(F7)命令编译链接程序,程序运行后将在程序视 图区域显示文本串。 P140表4-1

例4_2:编写一个基于对话框的应用程序MyDialog,程序运行后 显示一个对话框。 编程说明与实现: 1 . 执 行 File | New 命 令 , 在 New 对 话 框 中 选 择 MFC AppWizard[exe]项,输入程序名MyDialog。单击OK按钮,出现 MFC AppWizard-Step 1。 2. 在MFC AppWizard-Step 1中选择Dialog Based选项,单 击Next按钮,出现MFC AppWizard-Step 2 of 4。 3. 在MFC AppWizard-Step 2 of 4中设置应用程序界面特征。 4. 创建对话框应用程序后续的步骤与创建单文档或多文档 应用程序的Step 5和Step 6 相同。

4.1.3 MFC应用程序的开发流程
利用Visual C++编写Windows应用程序可以采取几种不同 的途径: 利用 Win32 应用程序接口 API( Application Programming Interface)提供的函数,用C或C++语言编写程序。
?

由于 MFC 通过类对API的绝大部分功能进行了封装,可以 利用 MFC ,用 C++ 语言编写程序。
? ?利用

MFC 和 MFC AppWizard[exe],首先利用 MFC AppWizard[exe] 应用程序向导生成基本的应用程序框架,然 后按照 MFC 机制和原理向框架添加具体的应用代码。

编写一个实现具体功能的MFC应用程序的步骤:
?

根据应用程序特性在MFC AppWizard[exe]应用程序向导各 步骤对话框中进行选择,创建一个应用程序的框架。

?

利用资源编辑器为程序编辑或添加资源,如编辑菜单、添 加对话框等。
利用ClassWizard类向导或手工添加类、成员变量和成员函 数的声明。 根据需要编写具体的函数代码。 编译、链接程序。如果程序有语法错误,需要修改源程序。 直到没有编译、链接错误,才能得到可执行程序。 测试应用程序各项功能,如果程序没有实现程序设计所要 求的功能,启动Debug调试器进行调试,找出并修改程序设 计中的逻辑错误。

?

? ?

?

ClassWizard类向导: Visual C++ IDE为MFC提供了大量的支持工具,除了MFC AppWizard[exe]向导,还提供了ClassWizard类向导,利用它程 序员可以方便地增加或删除对某个消息的处理。 资源编辑器: 为程序添加具体的代码时还经常要用到资源编辑器。 下图形象地说明了编写一个MFC应用程序的流程、所用到 的工具及主要生成的文件。

CLW

编程时,除了编辑现有的资源,有时需要向项目添加新的 资源,这时可以利用Insert菜单创建一个新的资源。 打 开 Insert 菜 单 , 选 择 Resource 菜 单 项 , 出 现 Insert Resource对话框,如下图所示,在Resource Type框中选择一个 资源类型,单击New按钮即可向项目添加一个资源。

4.2 应用程序向导生成的文件
MFC类库将所有图形用户界面的元素如窗口、菜单和按 钮等都以类的形式进行了封装,编程时需要利用C++类的继 承性从MFC类中派生出自己的类,实现标准Windows应用程 序的功能。 MFC AppWizard[exe]向导对Windows应用程序进行了 分解,并利用MFC的派生类对应用程序重新进行了组装,同 时还规定了应用程序中所用到的MFC派生类对象之间的相互 联系,这就是向导生成的MFC应用程序框架。MFC应用程序 框架实质上是一个标准的Windows应用程序,它具有标准的 窗口、菜单栏和工具栏。

4.2.1 应用程序向导生成的文件类型
为了生成一个可执行程序,MFC AppWizard[exe]向导必 须首先创建一个项目,并为项目生成一系列初始文件,如C++ 头文件、C++源文件、资源文件和项目文件,其中的C++文件 都是以MFC派生类为单元来组织的。 Visual C++中的文件类型很多,根据项目类型不同而产生 不同类型的文件。下面列出了MFC AppWizard[exe]应用程序 向导生成的文件类型。当进行编辑、编译和链接时,还要生成 一些临时文件。

MFC AppWizard[exe]向导生成的文件类型
后缀 dsw dsp h cpp rc rc2 ico bmp clw ncb opt 类型 工作区文件 项目文件 C++头文件 C++源文件 资源脚本文件 资源文件 图标文件 位图文件 类向导文件 没有编译的浏览文件 可选项文件 说明 将项目的详细情况组合到工作区中 存储项目的详细情况并替代mak文件 存储类的定义代码 存储类的成员函数的实现代码 存储菜单、工具栏和对话框等资源 用来将资源包含到项目中 存储应用程序图标 存储位图 存储ClassWizard类向导使用的类信息 保留ClassView和ClassWizard使用的详细情况 存储自定义的WorkSpace工作区中的显示情况

?

MFC AppWizard[exe]向导为一般的SDI应用程序生成了五个类,

这些类都是MFC类的派生类。这里的“一般的SDI应用程序”是指向 导每一步都采用默认选项,如不支持数据库和OLE对象等。
?

一般应用程序框架中所有类的名字由MFC AppWizard[exe]向导根

据一定的规则自动命名,但用户可以在向导的第6步改变类名和有关 类的文件名。应用程序框架中类(框架窗口类例外)的命名规则一般

遵照如下要求:
Class Name = C + ProjectName + ClassType

? ? ? ?

一般而言,C++中的一个类由头文件h和源文件cpp两类文件支持。 头文件用于定义类,包括指明派生关系、声明成员变量和函数。

源文件用于实现类,主要定义成员函数的实现代码和消息映射。
例如,应用程序视图类CMysdiView的两个支持文件是MysdiView.h 和MysdiView.cpp。

4.2.2 应用程序向导生成的头文件
除了CAboutDlg类,应用程序向导为框架窗口类、文档类、 视图类和应用程序类等4个类生成了头文件。 注:在定义类的头文件中的开始位置(类的正式定义前) 有一段预处理命令代码,这些代码是为Developer Studio自身 准备的,如用于保证头文件在编译时仅被编译一次。 Developer Studio中的资源编辑器、ClassWizard类向导和编译 器都可能用到这些代码。这些代码如下形式所示:
#if !defined (AFX_MAINFRM_H__4A1FE89D_3AF4_4C81_8341_E B0D3FE4E5D1__INCLUDED_) #define AFX_MAINFRM_H__4A1FE89D_3AF4_4C81_8341_EB0D3 FE4E5D1__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000

1. 框架窗口类头文件
?

向导为项目Mysdi生成了框架窗口类的头文件MainFrm.h, 该头文件用于定义框架窗口类CMainFrame。不同的SDI应用 程序,其框架窗口类名和文件名是统一的。 CMainFrame类是MFC的CFrameWnd类的派生类,它主要 负责创建标题栏、菜单栏、工具栏和状态栏。
CMainFrame类中声明了框架窗口中的工具栏m_wndToolBar、 状态栏m_wndStatusBar两个成员变量和四个成员函数。

?

?

2. 文档类头文件 向导为项目Mysdi生成了文档类的头文件MysdiDoc.h,该 头文件用于定义文档类CMysdiDoc。CMysdiDoc类是MFC的 CDocument类的派生类,它主要负责应用程序数据的保存和装 载,实现文档的序列化功能。

3. 视图类头文件
?

向导为项目Mysdi生成了视图类的头文件MysdiView.h,该头 文件用于定义视图类CMysdiView。视图类用于处理客户区 窗口,它是框架窗口中的一个子窗口。 CMysdiView类是MFC的CView类的派生类,它主要负责客 户区文档数据的显示,以及如何进行人机交互。

?

4. 应用程序类头文件 向导为项目Mysdi生成了应用程序类的头文件Mysdi.h,该 头 文 件 用 于 定 义 应 用 程 序 类 CMysdiApp。CMysdiApp 类 是 MFC的CWinApp类的派生类,它主要负责完成应用程序的初 始化、程序的启动和程序运行结束时的清理工作。

5. 资源头文件
?

在项目中,资源通过资源标识符加以区别,通常将一个项目 中所有的资源标识符放在头文件Resource.h中定义。
向导为项目Mysdi生成了资源头文件Resource.h,该文件用于 定义项目中所有的资源标识符,给资源ID分配一个整数值。 标识符的命名有一定的规则,如IDR_MAINFRAME代表有 关主框架的资源,包括主菜单、工具栏及图标等。标识符以 不同的前缀开始,见下表。
IDR_ IDD_ IDC_ IDS_ IDP_ ID_ 主菜单、工具栏、应用程序图标和快捷键表 对话框 控件和光标 字符串 提示信息对话框的字符串 菜单命令项

?

?

6. 标准包含头文件
?

向导为项目Mysdi生成了标准包含头文件StdAfx.h,该文件用 于包含一般情况下要用到且不会被修改的头文件,如MFC类 的声明文件afxwin.h、使用工具栏和状态栏的文件afxext.h, 这 些 头 文 件 一 般 都 存 放 在 路 径 “ … \ Microsoft Visual Studio\VC98\MFC\Include”下。 StdAfx.h文件和StdAfx.cpp文件用来生成预编译文件。

?

4.2.3 应用程序向导生成的源文件
?

对应于一个头文件中定义的类,都有一个类的实现源文件。
在实现文件中主要定义在头文件中声明的成员函数的实现代 码和消息映射。MFC AppWizard[exe]生成的实现文件也包 括六种。

?

值得说明的是,向导生成的成员函数有很多,不要因为没有 使用某个成员函数而删除其声明和实现代码。并且,用户一 般不要轻易修改文件中那些以灰色字体显示的代码,因为这 些代码是通过资源编辑器或ClassWizard类向导进行维护的。

1. 框架窗口类源文件
向导为项目Mysdi生成了框架窗口类的实现文件Mainfrm.cpp,该 文 件 包 含 了 窗 口 框 架 类 CMainFrame 的 实 现 代 码 , 主 要 是 CMainFrame类成员函数的实现,它实现的框架窗口是应用程序的主 窗口。

CMainFrame类的四个主要成员函数:
?AssertValid():诊断CMainFrame对象是否有效,调试用。 ?Dump():输出CMainFrame对象的状态信息,调试用。

?OnCreate(): 响 应 WM_CREATE 的 消 息 处 理 函 数 。 创 建 工 具 栏

m_wndToolBar 和 状 态 栏 m_wndStatusBar。 而 视 图 窗 口 是 由 基 类 CFrameWnd的成员函数OnCreate()通过调用OnCreateClient()函数 创建的。
?

PreCreateWindow():如果要创建一个非默认风格的窗口,可以重 载该函数(虚函数),在函数中通过修改CREATESTRUCT结构参 数cs来改变窗口类、窗口风格、窗口大小和位置等。
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

CREATESTRUCT结构定义了创建函数创建窗口所用的初始参数 ,其定义如下: typedef struct tagCREATESTRUCT { LPVOID lpCreateParams; // 创建窗口的基本参数 HANDLE hInstance; // 拥有将创建的窗口的模块实例句柄 HMENU hMenu; // 新窗口的菜单句柄 HWND hwndParent; // 新窗口的父窗口句柄 int cy; // 新窗口的高度 int cx; // 新窗口的宽度 int y; // 新窗口的左上角Y坐标 int x; // 新窗口的左上角X坐标 LONG style; // 新窗口的风格 LPCSTR lpszName; // 新窗口的名称 LPCSTR lpszClass; // 新窗口的窗口类名 DWORD dwExStyle; // 新窗口的扩展参数 } CREATESTRUCT;

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs // 修改主窗风格 cs.style &= ~FWS_ADDTOTITLE; //去除标题条中的文档名 cs.style &= ~WS_THICKFRAME; //去除可改变大小的边框 cs.style |= WS_DLGFRAME; //增加不能改变大小的边框 // 确定主窗的大小和初始位置 int cxScreen = ::GetSystemMetrics(SM_CXSCREEN);//获得屏幕宽 int cyScreen = ::GetSystemMetrics(SM_CYSCREEN); //获得屏幕高 cs.x = 0; // 主窗位于左上角 cs.y = 0; cs.cx = cxScreen/2; // 主窗宽为1/2屏幕宽 cs.cy = cyScreen/2; // 主窗高为1/2屏幕高

return TRUE;
}

例4_3:修改程序Mysdi,使程序运行窗口没有最大化按钮。 在项目工作区ClassView页面打开CMainFrame类,双击成 员函数PreCreateWindow()在编辑窗口打开该函数,添加代码:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; // TODO: Modify the Window class or styles here cs.style&=~WS_MAXIMIZEBOX; // 取消窗口的最大化按钮 return TRUE; }

习题:24

2. 文档类源文件
向导为项目Mysdi生成了文档类的实现文件MysdiDoc.cpp。 与框架类CMainFrame类似,文档类CMysdiDoc也定义了两个用 于调试的成员函数AssertValid()和Dump。
文档类CMysdiDoc的成员函数: ? AssertValid() ? Dump() ? OnNewDocument():当用户执行File菜单中New命令时,MFC应 用程序框架会调用函数OnNewDocument()来完成新建文档的工作。 ? Serialize():负责文档数据的磁盘读写操作。(第5章)
?

由于SDI单文档应用程序中只处理一个文档对象,当执行New命令时, 文档对象已经生成,因此文档类CMysdiDoc的构造函数不会再被调 用。所以,SDI应用程序不要在构造函数中进行文档对象成员变量 的初始化,而应在OnNewDocument()函数中。 ? 在文档派生类CMysdiDoc重载的OnNewDocument()函数中,首先需 要调用基类CDocument的OnNewDocument()函数。

3. 视图类源文件
向导为项目Mysdi生成了视图类的源文件MysdiView.cpp, 该文件主要定义了视图类的成员函数。视图对象用来显示文档 对象的内容。与框架类和文档类一样,视图类CMysdiView也定 义了两个用于调试的成员函数AssertValid()和Dump()。
视图类CMysdiView的成员函数:
?

GetDocument():用于获取当前文档对象的指针m_pDocument。 如果是建立程序的Release发行版,函数GetDocument()作为内嵌 (inline)函数来实现。

CMysdiDoc* CMysdiView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMysdiDoc))); return (CMysdiDoc*)m_pDocument; }

?

OnDraw():虚函数,它负责文档对象的数据在用户视图区的显示 输出。

void CMysdiView::OnDraw(CDC* pDC) { CMysdiDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here }

例4_4:修改程序Mysdi,为CMysdiDoc文档类定义一个字符串类 型的成员变量,在OnNewDocument()函数中初始化成员变量。在 OnDraw()函数中访问该成员变量,并在屏幕上输出它的值。
(1)在头文件MysdiDoc.h文档类CMysdiDoc的定义中增加成员变量 m_szText,用于保存将要显示的文本信息:

public: char* m_szText; ( 2 ) 在 文 档 类 实 现 文 件 MysdiDoc.cpp 中 找 到 成 员 函 数 OnNewDocument(),添加初始化m_szText的代码:

BOOL CMysdiDoc::OnNewDocument( ) { if (!CDocument::OnNewDocument()) return FALSE; // TODO: add reinitialization code here, … m_szText = “这是一个单文档程序!”; return TRUE; }

// 初始化

(3)在视图类实现文件MysdiView.cpp中找到成员函数OnDraw(),向导 创建的函数框架中已自动添加了函数GetDocument()的调用语句,以获 取与当前视图相关联的文档指针pDoc。手工添加如下代码,通过pDoc访 问文档类CMysdiDoc的成员变量m_szText,用于在屏幕上输出。
void CMysdiView::OnDraw(CDC* pDC) // pDC是输出设备环境的指针 { CMysdiDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // 得到当前文档指针pDoc // TODO: add draw code for native data here pDC->TextOut(100, 100, pDoc->m_szText); // 通过pDoc访问文档对象的成员变量 习题:25 }

4. 应用程序类源文件
向导为项目Mysdi生成了应用程序类的实现文件Mysdi.cpp,该 文件是应用程序的主文件,MFC应用程序的初始化、启动运行和结 束都是由应用程序对象完成。
在Mysdi.cpp文件中定义了应用程序类CMysdiApp的成员函数, 以下列出了应用程序类实现文件Mysdi.cpp的部分源代码。
BEGIN_MESSAGE_MAP(CMysdiApp, CWinApp) //{{AFX_MSG_MAP(CMysdiApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout) // ClassWizard将在此处添加和删除消息映射宏 . . . . . . END_MESSAGE_MAP() // CMysdiApp construction CMysdiApp::CMysdiApp() { // TODO: 在此处添加构造函数代码 // 把所有的重要的初始化信息放在InitInstance过程当中 // 声明唯一的CMysdiApp对象theApp CMysdiApp theApp;

}

// CMysdiApp的初始化 BOOL CMysdiApp::InitInstance() { // 标准初始化 WinMain()主函数是应用程序的入口点,在源程序中看 // 如果不使用这些特征并希望减少最终可执行代码的长度, 不见,自动连接. // 可以去掉以下专门的初始化代码。 . . . 全局变量theApp // 设置应用程序的注册键 InitInstance()函数的任务:P152 // TODO: 应该为这个字符串设置适当的内容,如公司名或组织名 SetRegistryKey(_T("Local AppWizard-Generated Applications")); // 装入应用程序INI文件中的设置信息,如 “最近使用的文件列表” 项 LoadStdProfileSettings(); // 注册应用程序文档模板,文档模板用于链接文档、框架窗口和视图 CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CMysdiDoc), RUNTIME_CLASS(CMainFrame), // SDI框架窗口 RUNTIME_CLASS(CMysdiView)); AddDocTemplate(pDocTemplate); . . . // 主窗口已经初始化,在此显示并刷新窗口 m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow(); return TRUE;

5. 标准包含文件
向导为项目Mysdi生成了标准包含文件StdAfx.cpp,该文 件用于包含StdAfx.h标准包含头文件。StdAfx.cpp文件用于生 成项目的预编译头文件(Mysdi.pch)和预编译类型信息文件 (StdAfx.obj)。 由于大多数MFC应用程序的实现文件都包含StdAfx.h头文 件(其中包含了一些共同要使用的头文件),如果在每个实现 文件中都重新编译StdAfx.h头文件,整个编译过程将浪费大量 的时间。为了提高编译速度,可以首先将项目中那些共同要使 用的头文件编译出来,首次编译后将结果存放在一个名为预编 译头文件的中间文件中,以后再编译时直接读出存储的结果, 无需重新编译,节约了编译时间。

4.2.4 应用程序向导生成的资源文件
Windows编程的一个主要特点是资源和代码的分离,即将 菜单、工具栏、字符串表、对话框等资源与基本的源代码分开。 优点:
? 这样使得对这些资源的修改独立于源代码。例如,可以将字

符串表翻译成另一种语言,而无需改动任何源代码。
? 当Windows装入一个应用程序时,一般情况下,程序的资源

数据并不同时装入内存,而是在应用程序执行过程中需要时如 创建窗口、显示对话框或装载位图,才从硬盘读取相应的资源 数据。

1.资源文件 向 导 为 项 目 Mysdi 生 成 了 资 源 文 件 Mysdi.rc 和 Mysdi.rc2。Mysdi.rc 是 Visual C++生成的脚本文件,它使用标准的Windows资源定义语句,可通过资 源编译器转换为二进制资源。一般利用资源编辑器对资源进行可视化编辑, 也可通过Open命令以文本方式打开一个资源文件进行编辑。Mysdi.rc2文件一 般用于定义资源编辑器不能编辑的资源。 2.图标文件

向导为项目Mysdi生成了应用程序的图标文件Mysdi.ico。在Visual C++中, 可利用图形编辑器编辑应用程序的图标。 3.文档图标文件 向导为项目Mysdi生成了文档图标文件MysdiDoc.ico。文档图标一般用于 多文档应用程序中,在程序Mysdi中没有显示这个图标,但编程时用户可以利 用相关函数来获取该图标资源并显示图标(ID为IDR_MYSDITYPE)。 4.工具栏按钮位图文件 向导为项目Mysdi生成了工具栏按钮的位图文件Toolbar.bmp,该位图是 应用程序工具栏中所有按钮的图形表示。

例4_5:在视图区显示文档图标。
void CMysdiView::OnDraw(CDC* pDC)

{
CMysdiDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here HICON hDocIcon= AfxGetApp()->LoadIcon(IDR_MYSDITYPE); pDC->DrawIcon(10,10,hDocIcon); }

习题:26

4.2.5 应用程序向导生成的其他文件
除了上述用于生成可执行程序的源代码文件和资源文件,向 导还为项目生成了其它一些在开发环境中必须使用的文件,如项 目文件、项目工作区文件和ClassWizard类向导文件。 1.项目文件

项目用项目文件DSP(Developer Studio Project)来描述, 向导为项目Mysdi生成了项目文件Mysdi.dsp,该文件将项目中的 所有文件组织成一个整体。项目文件保存了有关源代码文件、资 源文件以及你所指定的编译设置等信息。 2.工作区文件 为了创建应用程序,必须在Developer Studio的工作区中打开 项目,这些应用程序项目工作区设置信息保存在项目工作区文件 DSW(Developer Studio Workspace)中。向导为项目Mysdi生

成了项目工作区文件Mysdi.dsw,该文件将一个DSP项目文件与

具体的Developer Studio结合在一起,它保存了上一次操作结束 时窗口状态、位置以及工作区设置信息。
3.类向导文件

向导为项目Mysdi生成了类向导文件Mysdi.clw,该文件存 储了ClassWizard类向导使用的类信息,如类信息的版本、类的 数量、每个类的头文件和实现文件。利用ClassWizard类向导时 要 使 用 该 文 件 。 如 果 从 项 目 中 删 除 了 clw 文 件 , 下 次 使 用 ClassWizard类向导时会出现提示对话框,询问是否想重新创建 这个文件。
4.项目自述文件 Readme.xt该文件介绍了向导所创建文件的内容和功能,并 告诉用户在什么位置添加自己的代码以及如何更改资源语言。

4.3
?

ClassWizard类向导

利用应用程序向导生成MFC应用程序框架后,用户需要为

自己的MFC派生类添加消息处理成员函数和对话框控件的
成员变量,有时还需要为程序添加新的MFC派生类,这时 用户需要使用ClassWizard类向导。
?

MFC ClassWizard类向导根据程序员的要求以半自动的方
式添加程序代码,它是进行MFC应用程序设计时一个必不 可少的交互式工具,在今后的程序设计中经常用到它。

4.3.1 ClassWizard的功能
?

定制现有的类和建立新的类,如把消息映射为类的成员函数, 把一个控件与类的成员变量关联起来。 用户编程时,利用ClassWizard类向导能够大大简化一些细节 问题,如成员变量和成员函数的声明和定义放在何处、成员 函数如何与消息映射联系在一起。

?

?

ClassWizard有五个页面:Message Maps页面用来处理消息映 射,为消息添加或删除处理函数;Member Variables页面用 来给对话框类添加或删除成员变量(与控件关联); Automation页面提供了对OLE自动化类的属性和方法的管理; ActiveX Events页面用于管理ActiveX类所支持的ActiveX事件; Class Info页面显示应用程序中所包含类的信息。

4.3.2 添加消息处理函数
ClassWizard类向导的Message Maps页面主要用于添加 与消息处理有关的代码,包括添加消息映射宏和消息处理函 数。Message Maps页面有五个列表框:
? ?

Project框列出当前工作区中的项目 Class name框列出当前项目中的类

?
? ?

Object IDs框列出当前类所有能接收消息的对象(ID), 包括类、菜单项和控件
Messages框列出在Object IDs框中选择的对象可处理的消 息和可重载的MFC虚函数 Member functions框列出当前类已创建的消息处理函数, 其中的“V”标记表示该函数是虚函数,“W”标记表示该函 数是窗口消息处理函数

添加、编辑、删除成员函数
当在Messages框选择一个消息后:
? ? ?

单击Add Function按钮添加一个消息处理函数。 单击Edit Code按钮将退出ClassWizard,打开源代码编辑器 并定位到指定的消息处理函数。 单击Delete Function按钮可以删除已建立的消息处理函数。 注意:为了避免不小心删除了函数代码,此时只在头文件中 删除了函数声明,在源文件中删除了消息映射项,实际的函 数代码必须用户自己手工删除。

例4_6:编写一个SDI应用程序MyMessage,程序运行后在程序 视图窗口左击或右击鼠标时分别弹出不同提示信息的对话框,显 示左击或右击鼠标的次数。
1. 利用MFC AppWizard[exe]建立一个单文档应用程序MyMessage。 2. 为视图类CMyMessageView添加两个private属性、int类型的成员变 量 m_nLeft 和 m_nRight。 在 项 目 工 作 区 的 ClassView 类 视 图 中 右 击 CMyMessageView,在弹出式菜单中选择Add Member Variable命令项 出现添加成员变量对话框,在对话框中输入变量类型和变量名、选择 属性。也可以采用手工方法直接在头文件中添加一般的成员变量。

3.在视图类CMyMessageView的构造函数中添加初始化成员变量的代码:

CMyMessageView::CMyMessageView() { // TODO: add construction code here m_nLeft=0; // 初始化成员变量 m_nRight=0; }
4.分别添加鼠标左击或右击的消息处理函数。 按Ctrl+W键弹出MFC ClassWizard对话框,选择Message Maps页 面。在Class name和Object IDs框选择CMyMessageView,在Messages 框分别选择WM_LBUTTONDOWN和WM_RBUTTONDOWN消息, 单击Add Function按钮。最后单击OK按钮退出MFC ClassWizard对话 框。 ClassWizard类向导完成的工作: 在 视 图 类 CMyMessageView 的 头 文 件 中 声 明 了 消 息 处 理 函 数 OnLButtonDown()和OnRButtonDown();
?

在视图类CMyMessageView的实现文件中生成了消息处理函数的框 架代码;
? ?

在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP中定义了 消 息映射。 5. 在消息处理函数OnLButtonDown()和OnRButton-Down()中指定位置 添加如下代码,以累加左击或右击鼠标的次数,并弹出一个信息框。

void CMyMessageView::OnLButtonDown (UINT nFlags,CPoint point) { // TODO: Add your message handler code here m_nLeft++; // 左击鼠标次数加一 CString strOutput; // 产生用于输出的格式化字符串 strOutput.Format("The times of left button down: %d", m_nLeft); MessageBox(strOutput); // 弹出提示信息框 CView::OnLButtonDown(nFlags, point); }

void CMyMessageView::OnRButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default m_nRight++; CString strOutput; strOutput.Format("The times of right button down:%d",m_nRight); MessageBox(strOutput); CView::OnRButtonDown(nFlags, point); } 添加一般的成员函数除了采用手工方法直接在头文件和实现文件 中分别添加函数声明和函数代码外,也可以在Workspace项目工作区 ClassView 页 面 中 右 击 鼠 标 , 从 弹 出 式 菜 单 项 执 行 Add Member Function命令。

习题:27、28

4.3.3 为项目添加新类
?
?

利用ClassWizard类向导为项目添加一个常用MFC类的派生类。

选择执行“Insert|New Class…”菜单命令添加: (1)其它MFC类的派生类 (2)非MFC类的派生类 (3)普通类
利用ClassWizard类向导添加新类 利用“Insert|New Class”命令添加类

删除类:
? ?

首先利用资源管理器把头文件和源文件删除或移走; 然后重新打开ClassWizard类向导,在Class name下拉列表框

中选择已删除的类时,系统将给出信息框,提示类找不到的信 息,并提示是删除这个类还是改变与这个类对应的文件,单击 Remove按钮从项目中删除这个类。

习题:29

4.4 程序调试
程序调试是程序设计中一个很重要的环节,一个程序要 经过很多次调试才能保证其基本正确。 程序调试分为源程序语法错误的修改和程序逻辑设计错 误的修改两个阶段。编译器只能找出源程序语法上的错误, 程序逻辑设计上的错误只能靠程序员通过一些调试工具来手 工检查和修改。 程序调试水平的高低与程序员的经验密切相关,程序调 试水平也决定了程序员的编程能力,程序员在实际编程中应 该熟练掌握各种调试工具的使用。

4.4.1 查找源程序中的语法错误
对于程序中的语法错误,直接利用高级语言编译器就能找出 来。如果程序有语法错误,则在执行编译、链接命令时,Visual C++编译器将在Output输出窗口给出语法错误提示信息。 错误提示信息的格式为: <源程序路径> (行):<错误代码> :<错误内容说明> 例如: D: \例4-6 MyMessage\MyMessageView.cpp(38) : error C2065: 'm_nLeft' : undeclared identifier 错误代码给出了源代码语法错误类别和编号,语法错误分为 一般错误(error)和警告错误(warning)两种。
?

error错误出现的情况:如少写一个括号、分号或写错一个单 词或大小写错误,变量、函数未定义或重定义,没有包含需 要的头文件等,属于语法错误。当出现error错误时将不会产 生可执行程序。

?

warning错误出现的情况:如一个定义的变量没有使用、一个 浮点值被赋值给一个整形变量,以及main()函数有返回值却 没有给出等。出现warning错误时可生成可执行程序。

提示: 编译器给出的错误提示信息可能不十分准确,并且一处错误往往会引出若 干条错误提示信息,一个有经验的程序员根据这些信息就能够判断具体的错 误位置,修改一个错误后马上进行程序的编译和链接。通过重复的编译和链 接,使程序中的错误越来越少,直至所有的错误都被修改。
?

在链接阶段也可能给出错误提示信息,链接错误提示信息不给出错误发生 的具体位置,因为链接的程序是目标文件(obj),无法确定错误发生的准 确位置。发生链接错误时,一般是程序中调用了某个函数,而链接程序却找 不到该函数的定义。另外,程序分为几个文件分别编译、链接时,可能出现 全局变量没有声明或重复声明的错误。
?

在Output窗口中双击错误提示信息可以返回到源程序编辑窗口,并通过 一个箭头符号定位到产生错误的语句。在Output窗口选择一条错误提示信息 后,单击F1键可打开MSDN联机帮助,显示该错误代码更详细的说明和有关 的例子。
?

4.4.2 Debug调试器
Visual C++ 提 供 了 一 个 调 试 工 具 ─ Debug 调 试 器 。 利 用 Debug调试器可以在开发程序时方便快捷地进行程序的调试。 Debug调试器功能: ? 设置断点 ? 单步跟踪 ? 观察变量、表达式和函数调用关系

即使程序没有设计错误,也可以使用Debug调试器分析任 何一个程序的执行过程,这对于学习 MFC应用程序框架的工 作原理以及如何定制自己的应用程序都是非常有用的。
Debug 和 Release 版
?

Debug版本生成的中间文件及可执行文件放在Debug子目录, 目标文件包含所有的调试信息,但不具有优化功能。

?

Release版本生成的文件放在Release子目录,目标文件不包含 任何调试信息,不能进行程序调试,但具有优化功能。

编程时一般先生成一个Debug调试版程序,程序经过调试确 认无误后,再编译、链接生成一个Release发布版程序。
“编译”?“配置” 启动Debug调试器 Build主菜单中有一个Start Debug子菜单,其中含有启动 Debug调试器的命令。如执行其中的Go(快捷键为F5)命令后, 程序便在调试器中运行,直到断点处停止。 启动调试器后,Debug菜单取代Build菜单出现在菜单栏中, 同时出现一个停靠的Debug工具栏和一些调试窗口,如下图所 示。

调试窗口
?

除了Debug工具栏,Debug调试器还提供了一些辅助窗口,用于显 示程序的调试信息。调试窗口汇集了许多信息,但通常并不需要观 察所有信息,而且有限的屏幕空间也限制了打开窗口的个数。

?

一般情况下,当进入程序调试时,除了打开常见的Output输出窗口, Debug调试器还自动打开Variable和Watch窗口。 Output输出窗口:显示有关Build和Debug操作的信息,包括编译链 接错误提示信息和调试时一些调试宏的输出信息。 Variable变量窗口:用于观察和修改某个作用域内所有变量的当前 值,调试器可根据当前程序运行过程中变量的变化情况自动选择应 显示的变量。该窗口有三个页面:

?

?

(1)Auto页面显示当前语句或前一条语句中变量的值和函数的返回值; (2)Locals页面显示当前函数中局部变量的值; (3)This页面以树型方式显示当前类的对象的所有数据成员,单击“+” 号可展开指针所指对象。

?

Watch查看窗口:用于观察和修改变量或表达式的值。单击Watch窗 口Name栏下的空白框,用户可添加新的要观察的变量或表达式。

4.4.3 跟踪调试可执行程序
跟踪调试程序是查找逻辑设计错误最常采用的动态方法。 跟踪调试的基本原理就是让程序按照源代码设计流程一步一步 地执行,通过观察和分析程序执行过程中数据和代码执行流程 的变化来查找程序设计的逻辑错误。
程序调试的几种方法:
? ? ?

在程序中人为设置断点,加入输出语句(传统方法)。
采用TRACE调试宏输出需要的信息(Visual C++)。 利用Visual C++ IDE集成调试器直接进行程序的跟踪调试, Debug调试器是其中最常用的调试器。

使用Debug调试程序最有效的手段
设置断点:在调试器中运行程序时可以强制程序执行到断 点处暂时停下来。
?

?

单步执行:使程序按照源代码的编写流程一行一行执行。

?

观察程序当前的数据变化情况:单步执行程序时通过观察调 试窗口中变量、表达式、调试输出信息和函数栈的内容了解 程序的运行情况。

跟踪调试时可以很方便地查看某个变量的值,只需将光 标在该变量上停留片刻,就会出现一个黄色的DataTips信息 框,显示光标所指变量的值。 例4_7:编写一个单文档应用程序Ellipse,程序运行后在程序视 图窗口根据所提供的参数绘制五个纵向排列整齐的椭圆。
void CEllipseView::OnDraw(CDC* pDC) { CEllipseDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);

int yLeft[5]={0,70,140,210,280}; int yRight[5]={70,140,210,280,350}; for ( int i=1; i<=5; i++) // 绘制五个纵向排列整齐的椭圆 pDC->Ellipse(100, yLeft[i], 300, yRight[i]); // 参数为椭圆外接矩形的左上角和右下角坐标 }

编译、链接并运行程序Ellipse,程序没有按要求绘制出五个 椭圆。为了找到错误所在,首先应该跟踪绘制椭圆的函数 OnDraw()。 ? 将光标移到OnDraw()函数的开头位置,单击工具栏最右端 手掌形状的按钮设置一个断点。按F5键启动Debug调试器并使 程序运行到断点处暂停,然后通过不断按F10键单步跟踪执行程 序,在单步执行过程中观察椭圆参数的实际值。 ? 我们发现当i=1时,yLeft[i]=70,yRight[i]=140,不是原意所 要求的0和70。继续单步执行,当i=5时,yLeft[i]=7806880, yRight[i]=0,更不是我们所设置的参数,如下图所示。
?

习题:30、31、32


相关文章:
第4章
袁龙友著 第 4 章 MFC 应用程序框架剖析 在进行一个 Windows 应用程序开发之...还记得我们在第二章中讲过的那个 创建窗口的程序(EX02-00)吗?创建一个窗口...
钢结构第4章作业参考答案
钢结构第4章作业参考答案_理学_高等教育_教育专区。钢结构第 4 章作业参考答案 4.1 验算由 2L63×5 组成的水平放置的轴心拉杆的强度和长细比。 轴心拉力的设计...
第4章 习题答案
第4 章 受弯构件的斜截面承载力 4.1 钢筋混凝土简支梁,截面尺寸 b ? h ? ...1 150 ? 164 .8kN hw 4 8 5 ? ? 2.2 ? 4 ,属于厚腹梁 b 220 ...
Lesson 02_MFC应用程序框架
9页 2财富值 3_第三章 MFC应用程序框架 13页 1财富值 第4章-MFC应用程序...Lesson 02 MFC 应用程序框架一,MFC 应用程序框架 1. 使用 AppWizard 创建第一...
第4章习题
第4章习题_文学_高等教育_教育专区。vc++1...(3) MFC 应用程序框架为状态栏定义的静态数组 ...(2) 为应用程序创建快捷菜单主要有哪些方法? 为...
ssh第4章第二讲
软件系 大二 本次课 学时 4 学时 第 4 章 ssh 框架整合 目的要求(含...sping 与 hibernate 的整合 首先,在 spring 中配置一个创建 sessionFactory 的 ...
第4章 系统构架设计
4.2系统技术架构设计 如今,N层应用程序已经成为构建企业级软件的标准。对于大多数...智能用电系统的框架设计 暂无评价 2页 ¥3.00 软件工程第4章结构化设计.....
第2章习题
第8章习题 暂无评价 2页 免费如要投诉违规内容,请到百度文库投诉中心;如要提出...( f ) (4) 使用 MFC AppWizard[exe]向导创建应用程序框架时,向导生成的文件...
第1-4章习题参考答案
第1-4章习题参考答案_理学_高等教育_教育专区。第...(fd,buf2,8); if(num!=8) printf("read less...在程序中将 umask 改至 044,创建文件 f4 #include...
计算机系统结构第4章部分习题参考答案
页式管理由操作系统进行, 对应用程序员是透明的。 ? 段页式管理-是段式管理和...第0组 第1组 1 主存块 2 3 4 5 6 7 C0 √√ C1 √√ C2 C3 √√...
更多相关标签: