VC6.0上基于MFC的应用开发软件架构3
² MFC简介:MFC是一个应用程序框架,专门为微软的Windows操作系统创建应用程序而设计。MFC使用抽象、封装、继承、多态性和模块化的面相对象原则,在逻辑上将Windows API分类: 通用类、Windows API类、应用程序框架类以及高层抽象等。下面将这几个分类展开介绍:
ü 通用类:提供类似字符串处理的类、集合类和异常类;
ü Windows API类:封装了所有的Windows APT,例如窗口类、对话框、设备环境类等等;
ü 应用程序框架类:处理整个应用程序中大的部分,封装了消息泵逻辑、打印、在线帮助和MFC的文档/视图结构;
ü 高层抽象:包括那些非基础的特性,如果工具栏、分割的窗口、状态栏。
MFC为几个操作系统扩展提供了支持,例如OLE、ODBC、简单MAPInfo和WinSock。
² MFC作用:
MFC将下面过程封装在一个类中:
Windows应用程序首先要有一个WinMain()函数,它是程序的入口点,应用通过它从Windows获得运行所必要的信息。包括应用程序的当前实例的句柄、应用程序的上一个运行实例的句柄、所有的命令行参数以及如何显示窗口等。应用程序至少要注册一个窗口类作为主窗口,将用户界面显示在屏幕上是Windows的工作。应用程序要建立消息循环;大多数应用程序需要一些初始化和安装。初始化有两种形式:针对应用程序的初始化和针对实例的初始化。应用程序必须提供消息处理函数,这个窗口过程函数至少要处理WM_DESTROY消息(除非应用程序永远都不停止)。
窗口消息基本形式: 所有窗口消息的基本形式都是一样的,其组成如下:
ü 一个无符号的整数:包含了消息的实际内容
ü WPARAM:一个4字节的参数
ü LPARAM:一个4字节的参数,常常包含额外数据或指向某个处理消息所需要的数据结构的指针
例如像WM_COMMAND消息,当某个菜单被选中、控件向它的父窗口发送通知代码等,窗口都会收到WM_COMMAND消息。参数WPARAM的低16位表示一个能够标志控件的号码,高16位是通知代码,表示像用户是否双击了控件这样的事件。LPARAM表示发送消息的控件的窗口句柄。
² 消息的分类:
ü 标准消息: 除WM_COMMAND之外,所有以WM_开头的消息。从CWnd派生的类,都可以接收到这类消息。
ü 命令消息: 来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。从CCmdTarget派生的类,都可以接收到这类消息。
ü 通告消息: 由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以
WM_COMMAND形式呈现。从CCmdTarget派生的类,都可以接收到这类消息。
² MFC消息处理:
MFC的消息处理结构由两个基本部分组成:CCmdTarget类和消息映射表。
CCmdTarget是所有接收窗口消息和命令的对象的基类;
消息映射表就是将窗口消息与处理消息的类成员函数关联起来的机制。
² MFC应用程序:
使用VC++6.0可以创建3种MFC应用程序:
ü 单文档应用程序
ü 多文档应用程序
ü 对话框应用程序
当使用应用程序向导创建单文档应用程序完成后,程序中会自动包含5个类:
ü CAboutDlg关于对话框类:管理关于对话框
ü C***App应用程序类:管理整个应用程序
ü C***Doc文档类:通常和视图窗口一同使用
ü C***View视图类:管理视图窗口
ü CMainFrame框架类:管理框架窗口
在四个类中都添加同一个命令响应函数,其响应顺序View,Doc,Frame,App。
实验步骤:
1. 打开VC6.0,在工程选项中选中MFC AppWizard,创建Dialog工程,选择单文档应用程序。打开类视图,则可以看到Dlg、App、Doc、View和Frame五个类视图。
2. 在资源视图中,右击Dialog,添加一个对话框。双击对话框,添加一个类Demo。在资源视图中,点击Menu,双击IDR_MAINFRAME,添加一个菜单,取名“复制”,将其ID号设置为IDM_COPY。
3. 右击“复制”添加事件响应函数,选择CMainFrame类,完成OnCopy()函数添加。然后在该函数中添加如下代码:Demo dlg ;dlg.DoModal ();
同时在选择的类中添加Demo.h头文件。
4. 利用控件来创建下面界面,粗体字代表该控件的ID的。
5. 添加事件的两种方法:
第一种方法在模板设计中,双击按钮,按确定后,即添加该按钮单击事件。
另一种方法是使用向导,首先在视图(View)菜单中选择类向导(ClassWizard),弹出类向导对话框,在类名(ClassName)下拉框中选择我们的要添加事件的类Demo。对象ID(Object ID)列表框中选择控件的ID,在消息(Messages)列表框中选择要添加的事件,按添加函数钮(Add Function)即可。
在Demo.cpp中包含头文件: #include <afxdlgs.h>
下面添加四个按钮事件函数:
ü void OnCancel();
在OnCancel()添加下面一句语句:this->EndDialog (ID_CANCEL);
这行语句的作用是关闭当前的对话框,并以IDCANCEL返回,表明用户是用取消来关闭对话框的。这是CDialog类的一个方法。我们期望如果点击了取消按钮,则关闭当前的对话框。
ü void OnSrbrowse();
添加OnSrbrowse()函数,代码为:
CFileDialog Open(true,"","",0,"All File|*.*|",this);
CString strFilePath;
if(Open.DoModal ()==IDOK)
{
strFilePath=Open.GetPathName ();
SetDlgItemText(ID_SOURCE,strFilePath);
}
ü void OnCopy();
添加OnCopy()函数,代码为:
CString strSource,strTarget;
GetDlgItemText (ID_SOURCE, strSource); //取得ID名为ID_SOURCE控件的文本
GetDlgItemText (ID_TARGET, strTarget); //取得ID名为ID_TARGET控件的文本
if (CopyFile (strSource, strTarget, false)) //复制文件,如果返回为真表示成功{
MessageBox ("复制成功!", "报告", MB_OK); //弹出一个确定框
}
ü void OnTrbrowse();
添加OnTrbrowse()函数,代码为:
CFileDialog Save(false,"", "",0 , "All File|*.*|", this );
CString strFilePath;
if (Save.DoModal() == IDOK){
strFilePath = Save.GetPathName();
SetDlgItemText (ID_TARGET, strFilePath);
}
6. 复制文本文件:
创建一个文本文件text1.txt和text2.txt,运行该程序,在源文件窗口中打开text1,在目标文件中打开text2,然后点击“复制”按钮。其将text1中的内容复制到text2中。
7. 测试命令响应顺序:
以同样的方法添加“测试”菜单,其ID号为IDM_TEST。分别在类CMainFrame、C****View、C****Doc和C****App添加函数OnTest();分别对四个类添加代码如下:
添加onText函数:
MessageBox("MainFrame clicked!");
MessageBox("View clicked!");
AfxMessageBox("Doc clicked!");
AfxMessageBox("App clicked!");
执行程序,当有消息框提示时,记录下该类。然后判断下一步运行到哪个类,方法是:将已运行的类中的OnTest的函数删除,再重新编译运行。
实验要求:
利用MFC实现将text1文件中的内容复制到text2文件中(注意修改实验步骤中控件的ID号);
在四个类中都添加同一个命令响应函数,测试View,Doc,Frame,App四个类的命令响应顺序。
测试结果:
部分代码:
// Demo.cpp : implementation file
/
#include "stdafx.h"
#include "Dialog.h"
#include "Demo.h"
#include <afxdlgs.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// Demo dialog
Demo::Demo(CWnd* pParent /*=NULL*/)
: CDialog(Demo::IDD, pParent)
{
//{{AFX_DATA_INIT(Demo)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void Demo::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(Demo)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(Demo, CDialog)
//{{AFX_MSG_MAP(Demo)
ON_BN_CLICKED(ID_COPY, OnCopy)
ON_BN_CLICKED(ID_TRBROWSE, OnTrbrowse)
ON_BN_CLICKED(ID_CANCEL, OnCancel)
ON_COMMAND(IDM_COPY, OnCopy)
ON_BN_CLICKED(ID_SRBROWSE, OnSrbrowse)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// Demo message handlers
void Demo::OnCancel()
{
// TODO: Add your control notification handler code here
this->EndDialog(ID_CANCEL);
}
void Demo::OnCopy()
{
// TODO: Add your control notification handler code here
CString strSource,strTarget;
GetDlgItemText(ID_SOURCE,strSource);
GetDlgItemText(ID_TARGET,strTarget);
if(CopyFile(strSource,strTarget,false)){
MessageBox("复制成功!","报告",MB_OK);
}
}
void Demo::OnTrbrowse()
{
// TODO: Add your control notification handler code here
CFileDialog Save(false,"","",0,"ALL File|*.*|",this);
CString strFilePath;
if(Save.DoModal()==IDOK){
strFilePath=Save.GetPathName();
SetDlgItemText(ID_TARGET,strFilePath);
}
}
void Demo::OnSrbrowse()
{
// TODO: Add your control notification handler code here
CFileDialog Open(true,"","",0,"ALL File|*.*|",this);
CString strFilePath;
if(Open.DoModal()==IDOK){
strFilePath=Open.GetPathName();
SetDlgItemText(ID_SOURCE,strFilePath);
}
}