转载地址:http://blog.sina.com.cn/s/blog_50d705670101hy8c.html

mfc框架中学习要诀

框架一般都会自动定义几个基本类:CinApp(应用程序类),CFrameWnd(主框架窗口类),Cview(视口类),CDocument(文档类);

其中mfc内部采用宏定义手法巧妙的“虚拟”了对象的多态机制,mfc最为关键的就是它的类继承机制,我们如果使用编译器(vs系列)创建工程,编译器会自动派生出上面几个类的子类,我们的操作就在这些子类派生的子类中完成,这种机制有一个好处:子类不不感兴趣的,基类会处理!

所以我们只需处理自己感兴趣的消息即可,在windows编程中,最主要就是消息,windows是通过消息来激励响应的事前处理程序的.

在win32的api编程中,我们是将消息处理函数通过窗口指定的回调函数来完成的,在mfc中,就不再采用这种结构化编程的手法;mfc在消息处理环节,巧妙的利用宏定义手法(其实可直接使用面向对象的多态机制完成!),采用所谓的消息映射,将消息以及消息处理函数和其他一些我们不关心的数据打包成一个结构体.所以,当我们的窗口收到消息时,通过遍历当前窗口类的消息映射表(就是上面说的结构体),找到对应消息的处理函数,然后就是直接跳处理函数完成消息映射,当在当前的窗口类的消息映射表中找不到所对应的消息时(说明我们对这个消息不关心,所以在本窗口类中没有写我们的处理函数),这时上面说的“类对象多态”机制的“mfc宏机制”就将这个我们不关心的消息发送给它的基类处理,当然基类也可以继续往上层基类发(这我们已经不关心,反正在这些“祖先”类中总会有类处理的!)

正是因为mfc的对象性质,所以使得一些人从结构化编程的win32 api编程转mfc的有些不习惯,在mfc中几乎所有的api函数都封装为了类,其中我们编译器自动生成的类中CinApp(应用程序类)负责应用程序内部初始化,CFrameWnd(主框架窗口类)负责“外壳”框架如菜单、状态栏等,Cview(视口类)主要用于显示数据如画图、写字,CDocument(文档类)主要负责内部数据的处理,所以在mfc中我们必须有一个思想:数据与显示应该是分开完成的!对于数据的处理我们应该放在CDocument(文档类)中完成,而显示时由Cview(视口类)负责!很多人却迷惑不知道如何这两个类“配合”起来!产生这种问题的原因,是对mfc框架还很陌生,并对面向对象的理解还不够!我们都知道类的函数都是对象调用的,所以只要在其中一个类中实例化另一个类的对象,自然就可访问另一个类的相关数据!mfc再复杂,还不得要具备面向对象的特征!所以别mfc吓到了,我们对面向对象的理解依旧可以用在mfc中,所以要想访问另一个类的数据,我们只需实例化一个该类的对象即可!所以,不要在问一些有如“如何获取另一个窗口的控件”之类的问题!

mfc的资源中,几乎都封装为类,比如菜单、状态栏、工具栏、按钮、编辑框等,这些东西在程序初始化时,被实例化为对象然后加载如框架类中,所以我所要说的就是这些资源都有类!在使用时只不过是实例化对象后引用该对象而已!完全就是面向对象的知识!知道了这些,我们就能完成一些人说所谓“很复杂”的东西!比如说:给按钮添加背景,做个不规则编辑框,带色泽的菜单之类的mfc原来没有提供给我们的东西!怎么做?当然是直接继承这些资源类,然后在我们自己的类中完成这些操作,在使用时实例化我们自己的类代替mfc提供的类即可,有些初学者在网上下载了一些大牛写的派生类后,不知道怎么用,其实就是自己对面向对象的认识不够!

在mfc中对控件的操作其实就是对对象的操作,我们在面向对象的学习中,对类的数据成员操作“了如指掌”,怎么到了mfc就不知道如何下手?因为这些数据成员都“披上了外衣”,这些所谓的控件不过就是一个数据成员而已!

初学者在mfc中不知道如何获取另一个窗体中控件或是其他的信息,其实还是面向对象的知识不牢固!想想看,在mfc中这些窗体都打包成了类,自然而然对窗体的操作就可通过实例化对象来完成,但这个时候,又有些初学者犯了面向对象的知识错误!譬如下面一个例子:

在窗口C中创建,对话框窗口A,并初始化了EDIT编辑框控件

要求在窗口B,修改窗口A的EDIT文本

很多初学者完全不知道从那入手!有点基础的就会这样做:

修改EDIT内容只要获取A的句柄然后::SetWindowText(::GetDlgItem(窗体A句柄,EDIT控件ID),文本)即可!所以这里的关键就是如何窗体A的句柄,这时就想到了m_hWnd,哦,每个窗体类的都会保存一个句柄,于是就在B窗体类出现以下代码:

a ha;
::SetWindowText(::GetDlgItem(ha.m_hWnd,EDIT控件ID),文本);

欣喜之余,激动的等待编译中……,可结果却是出乎想象!不是说MFC窗体、控件都是类吗?不是说类的成员就是通过控件访问吗?怎么会这样?其实还是对面向对象知识把握不牢固!并且混淆了类与窗体的关系!

首先:窗体A是在窗体C中创建的,也就是我们在窗体C对应的类中实例化了窗体A对应类的对象(注意用词),然后通过对象完成对EDIT编辑框控件的初始化!

所以:可以这样说,对现在的这个窗体A我们是通过C中实例化类A的对象来维护的!这时,你在B中进行a ha的操作是从新实例化一个A的对象,这个对象自然不是C中实例化的那个对象!!当然不能完成对C中实例化类A的对象进行操作!

这里:还要强调一点:窗体不等于类!窗体只是类实例化一个对象后的产物!

在win32 api 中我们都知道调用createwindow就可以创建一个窗体,但到了面相对象的MFC中,它就这个操作封装到一个类中,所以通过面向对象的知识我们就可以知道,我们要想创建窗体必须得实例化一个该类的对象,然后通过对象调用显示窗体的方法,所以这就是窗体与类的关系!!知道了这些,我们再次回答上的控件访问的问题之中:

原来窗体A是有窗体C中的一个类A的对象创建并维护的,所以,我们只要在窗体B获取窗体C的这个对象即可!还有问题?这个问题已经等于获取另一个类的成员!就如同,让你完成以下任务:

……

class a
{
int ai;
};
class c
{
int ci;
c();
a ha;
};
class b
{
int bi;
};
……
c::c()
{
ha.ai=10;
}
……

在C中实例化a的对象,并给类a的成员ai复制了,让你在类b中读取ai的值10 !

这样的问题,你还屑于做吗?可以用全局、静态等等,如果你学过设计模式,还可在类中定义方法,写出更为漂亮的代码~

原来玩mfc就是在玩面向对象的技术!以前学面向对象时,是不是曾经觉得什么类、对象、多态到底在程序中有什么用啊?我要学的是能开发QQ、鸽子之类软件的知识!不是那些在黑漆漆界面的东西!现在应该知道了,基础是很重要的!

所以:在mfc中难点在于了解mfc的消息映射机制,其他的都是面向对象的知识!!最后在说一句:别被MFC那“壮观”类构架吓到!只要你面向对象的学习过关了!吃透关键类 ,那么mfc就很简单!