深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建)
深入浅出MFC学习笔记
AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass *pNewClass) {
pNewClass->m_pNextClass = CRuntimeClass::pFirstClass; CRuntimeClass::pFirstClass = pNewClass; }
在 MFC 中保存了一棵类的家族树,CObject 是根结点,其他的类都是他的后代(有几个特 殊的除外,如: CPoint 等)。由于类的家族树存放的是类的信息——不是对象的信息,因此 只需要保存一个就够了,所以 MFC 将这棵树保存为 static 类型。
MFC 类的家族树和数据结构中的树并不相同,普通的树通过跟结点就可以访问所有的结点 (包括叶子)。但在 MFC 中却不行——它只能逆向地从叶子结点向根结点方向访问(从父 结点访问不到子结点)。
size_t n, size_t size, int (*cmp)(const void *keyval, const void *datum)); 想一想开发 bsearch 函数的人怎么会知道两个元素的是什么,怎么比较大小呢?因此就必须 留给用户要自己定义 cmp 函数了! 回调函数一般都有固定的格式(不知道是否会用变参数的情况),不然可能会发生错误。回
void main() {
A *pa = new B; pa->display(); }
执行的结果却打印是:class B
让人感觉不解的地方就是 pa 明明是类 A 的指针,却是执行了类 B 的函数(不可原谅)!!! 其实有这种感觉的人在不知不觉中就犯了一个形而上的错误:用 C 语言的函数行为来套用 display()的行为。在此我想提醒一点:把 C++当作一个新的语言,C 只是参考,不是金科玉 律,切记!!!
MFC学习笔记
MFC程序也有一个WinMain函数,这个函数是我们在编译链接的时候由链接器将WinMain函数链接进来的。
这个函数在APPMODUL.CPP中。
带有Afx的属于应用程序框架类的函数,应用程序框架是辅助我们生成应用程序的框架模型,这个框架模型把很多类或者类与类之间做了一个有机的集成提供给我们,我们可以根据框架模型提供的类库来设计我们自己的应用程序,Af即Application frame 看看这些类如何和我们WinMain函数关联到一起的?CmainFrame的名字是不会变的,其它的都是C+工程名+App/Doc/View命名。
class CTestApp : public CwinApp,可以看到CtestApp是从CwinApp派生出来的。
当我们双击CtestApp这个类时,我们可以看到VC++6.0上面显示我们进入了Test.h头文件中,当把CtestApp展开时,然后双击任何一个函数名,包括构造函数名,析构函数名…我们可以看到VC++6.0上面显示我们进入了Test.cpp源文件中。
且这种情况和我们直接从Fileview 资源卡中直接进入相应的头文件和源文件是一样的效果。
其它类也是相似的操作进入头文件和源文件。
不管是全局变量还是在全局对象CTestApp theApp;,它们都是在程序运行之前,也就是在入口函数WinMain函数加载之前,就已经为它们分配好了内存空间,作为全局函数,就要调用构造函数创建内存空间。
所以是先运行全局对象CTestApp theApp,调用它的构造函数,然后才运行WinMain。
为什么要定义一个全局对象呢?为什么要让它在WinMain之前完成呢?全局对象theApp又有什么作用?CtestApp是从CwinApp派生出来的,theApp是应用程序对象,是一个全局对象,每一个MFC程序当中有且仅有一个从CwinApp派生出来的类,也只能有一个应用程序类实例化的对象,它就表示了我们应用程序本身。
MFC四大关键技术
MFC六大关键技术(第四部分)——永久保存(串行化)先用一句话来说明永久保存的重要:弄懂它以后,你就越来越像个程序员了!如果我们的程序不需要永久保存,那几乎可以肯定是一个小玩儿。
那怕我们的记事本、画图等小程序,也需要保存才有真正的意义。
对于MFC的很多地方我不甚满意,总觉得它喜欢拿一组低能而神秘的宏来故弄玄虚,但对于它的连续存储(serialize)机制,却是我十分钟爱的地方。
在此,可让大家感受到面向对象的幸福。
MFC的连续存储(serialize)机制俗称串行化。
“在你的程序中尽管有着各种各样的数据,serialize机制会象流水一样按顺序存储到单一的文件中,而又能按顺序地取出,变成各种不同的对象数据。
”不知我在说上面这一句话的时候,大家有什么反应,可能很多朋友直觉是一件很简单的事情,只是说了一个“爽”字就没有下文了。
要实现象流水一样存储其实是一个很大的难题。
试想,在我们的程序里有各式各样的对象数据。
如画图程序中,里面设计了点类,矩形类,圆形类等等,它们的绘图方式及对数据的处理各不相同,用它们实现了成百上千的对象之后,如何存储起来?不想由可,一想头都大了:我们要在程序中设计函数store(),在我们单击“文件/保存”时能把各对象往里存储。
那么这个store()函数要神通广大,它能清楚地知道我们设计的是什么样的类,产生什么样的对象。
大家可能并不觉得这是一件很困难的事情,程序有能力知道我们的类的样子,对象也不过是一块初始化了存储区域罢了。
就把一大堆对象“转换”成磁盘文件就行了。
即使上面的存储能成立,但当我们单击“文件/打开”时,程序当然不能预测用户想打开哪个文件,并且当打开文件的时候,要根据你那一大堆垃圾数据new出数百个对象,还原为你原来存储时的样子,你又该怎么做呢?试想,要是我们有一个能容纳各种不同对象的容器,这样,用户用我们的应用程序打开一个磁盘文件时,就可以把文件的内容读进我们程序的容器中。
第3章 MFC编程基础知识
Visual C++ Program Design
MFC的设计原理 3.1.2 MFC的设计原理
MFC向软件开发者提供一组服务 , MFC 向软件开发者提供一组服务, 来协调应 向软件开发者提供一组服务 用程序。在很多情况下,MFC在幕后执行一系列 用程序 复杂的操作,它向程序员提供了更加简单的编程 界面,并可掩盖Windows API的一些缺点(MFC类 的许多成员函数,如MessageBox()中提供了缺省 参数,这减轻了程序员编程的负担)。 MFC 采用面向对象的设计方法 , 将 Windows API中的相关部分组合到 C++类或对象中 中的相关部分组合到C++ 类或对象中。 API 中的相关部分组合到 C++ 类或对象中 。 例如 CWnd类封装了大部分有关窗口处理的API 函数。 作为编程人员,不必记忆大量API 函数,需要作 的只是实例化CWnd类的一个实例,并调用相应的 成员函数即可。
Visual C++ Program Design
概述(续)
对于初学者,只需要清楚自己的代码往什么地方添加就可以 (5) 缺乏面向对象分析能力。面向对象的分析要求搞清楚一 个系统中有哪些类、各个类之间有哪些联系,尤其是在编写基于 文档/视图结构的应用程序时。该方面能力的培养要靠多分析一 些程序中类之间的关系,并要参考相关方面的书籍介绍。 本章把MFC类库中的主要类以层次结构做了一个简单的介绍, 并对MFC应用程序的架构做了描述。对于MFC应用程序的学习,刚 开始要“不求甚解”,懂得代码的放置以及原理就可以了,随着 学习的深入,在查看MFC源代码后,就能逐渐了解到该类型应用 程序的执行流程,从而最终掌握MFC应用程序的开发。
VC++6.0入门【第三章、MFC编程概述】
第三章 MFC 应用程序概述第3章 MFC 应用程序概述Microsoft Windows 是微软公司推出的一个应用于微机上的具有图形用户界面的多任务和多窗口的操作系统。
Windows 应用程序也称为窗口应用程序,所有的窗口应用程序都有着相同的窗口风格和菜单结构,用户界面友好,方便用户操作。
本章从剖析窗口应用程序的基本结构入手,继而介绍使用MFC 类库开发的应用程序框架结构,并介绍窗口应用程序运行的核心机制-消息映射。
学习了本章,你将对MFC 应用程序框架结构和运行机制有个整体的了解,为后面进入窗口应用程序开发打下良好的基础。
3.1 窗口应用程序概述窗口应用程序的开发一般采用可视化的面向对象的开发,可选择的窗口应用程序开发语言有Visual C++、Visual Basic 、Visual Java 、Dephi 等等。
无论采用哪一种开发语言,首先要了解窗口应用程序的基本机制。
3.1.1 窗口编程基础窗口应用程序运行于Windows 操作系统,Windows操作系统是一个多任务操作系统,因此窗口应用程序的组成,支持技术,基本运行机制等与DOS 应用程序有着本质的区别。
在学习开发窗口应用程序之前,先要对窗口应用程序有一个概念上的了解。
1. 窗口窗口是应用程序与用户进行交互的界面,应用程序通过窗口传递信息给用户,同样用户通过窗口输入数据,发布命令给应用程序。
Windows 界面包含了丰富的标准用户界面元素,包括窗口、图标、菜单、滚动条、对话框、控件和消息框等。
用户使用这些界面元素可以方便的与应用程序进行交互,一个典型的窗口外观如图3-1所示。
垂直滚动条 控制菜单栏 标题栏 菜单栏关闭按钮 最小化按钮 最大化按钮客户区VC++6简明教程图3-1 Windows应用程序窗口组成在Windows编程中,各种窗口、菜单、按钮、对话框及程序模块等Windows的规范部件是按“对象”来组织的。
为了提高开发窗口应用程序的效率,微软公司为用户提供了大量能创建上述标准元素的API函数和C++类,并且以Windows API函数库和C++类库的形式提供给用户,以充分满足构成应用程序操作界面的需要。
MFC六大关键技术
MFC六大关键技术是什么?1MFC程序的初始化过程2RTTI 动态类型标识3Dynamic Creation 动态生成4Persistence 永久保留5Message Mapping 信息映射6Message Routing 信息传递怎样自制RTTI?我们作为类库的设计者要在类构造起来的时候,记录必要的信息,以建立型录。
型录中的类的信息,最好以链表方式连接起来。
一般“类别型录”是一个结构,其中至少需要类名字,链表的Next 指针,以及链表的First指针。
First属于整体变量,一份就好,所以用static修饰。
为了将每一个类都能拥有成员变量集合,并且最好有一定的命名规则,然后经某种手段将整个类库构造好之后,“类别型录”(就是各个CRuntimeClass对象)则能呈现为:什么是DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC 宏?作用就是完成RTTI的“类别型录”。
为了将一个类对象塞到类之中,并定义一个可以捕捉到该对象地址的函数,定义一个宏为:#define DECLARE_DYNAMIC(class_name)public:static CRuntimeClass class##class_name;virtual CRuntimeClass* GetRuntimeClass()const;比如我使用了DECLARE_DYNAMIC(CView)编译器预处理器为我做出的代码是:public:static CRuntimeClass classCView;virtual CRuntimeClass * GetRuntimeClass()const;也就是定义类时,将类放入DECLARE_DYNAMIC宏就是把要放的对象放到了里边。
具体连接工作是由IMPLEMENT_DYNAMIC宏来实现:#define IMPLEMENT_DYNAMIC(class_name,base_class_name)_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)这里不做扩展,总之,IMPLEMENT_DYNAMIC内容不仅制定初值,它使用了一个struct AFX_CLASSINIT {AFX_CLASSINTI(CRuntimeClass * pNewClass);};(c++的struct和class都有构造函数):AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass*pNewClass){ pNewClass->m_NextClass = CRuntimeClass::pFirstClass; CRuntimeClass::pFirstClass = pNewClass;}就是上边的这个构造函数完成了连接工作。
3.MFC原理介绍
3.MFC原理介绍包括C++封装原理和MFC六⼤关键技术,以及类向导和MFC应⽤程序向导的使⽤⽅法。
讲解MFC消息映射机制的原理、消息映射函数的建⽴,以及消息发送和接收的⽅法。
CTime类,C语⾔中time函数void CTmDlg::OnButton1(){CTime t = CTime::GetCurrentTime();int nYear = t.GetYear();int nMonth = t.GetMonth();int nDay = t.GetDay();int nHour = t.GetHour();int nMin = t.GetMinute();int nSec = t.GetSecond();int nWeek = t.GetDayOfWeek();//周三CString str;str.Format("当前时间是:%d年%02d⽉%02d⽇ %02d:%02d:%02d",nYear,nMonth,nDay,nHour,nMin,nSec);//AfxMessageBox(str);SetWindowText(str);//SetTimer}void CTmDlg::OnButton2(){time_t tt = time(NULL);tm * pTime = localtime(&tt);int nYear = pTime ->tm_year+1900;int nMonth = pTime ->tm_mon+1;int nDay = pTime ->tm_mday;int nHour = pTime ->tm_hour;int nMin = pTime ->tm_min;int nSec = pTime ->tm_sec;CString str;str.Format("当前时间是:%d年%02d⽉%02d⽇ %02d:%02d:%02d",nYear,nMonth,nDay,nHour,nMin,nSec);//AfxMessageBox(str);SetWindowText(str);//SetTimer}类// MyTime.h: interface for the CMyTime class.////////////////////////////////////////////////////////////////////////#if !defined(AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_)#define AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000//⾯向对象(C++)特点:抽象,封装和派⽣,(多态)#include <time.h>class CMyTime{time_t m_time;public:int GetYear() const;static CMyTime GetCurrentTime();CMyTime();~CMyTime();};#endif // !defined(AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_)// MyTime.h: interface for the CMyTime class.////////////////////////////////////////////////////////////////////////#if !defined(AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_)#define AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_#if _MSC_VER > 1000#pragma once#endif// _MSC_VER > 1000//⾯向对象(C++)特点:抽象,封装和派⽣,(多态)#include <time.h>class CMyTime{time_t m_time;public:int GetYear() const;static CMyTime GetCurrentTime();CMyTime();~CMyTime();};#endif// !defined(AFX_MYTIME_H__A7F50C7B_E6B7_4ED5_BB03_E00EB9935406__INCLUDED_)#include "stdafx.h"#include <time.h>#include <stdio.h>#include "MyTime.h"int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){CMyTime t = CMyTime::GetCurrentTime();int nYear = t.GetYear();//CTime time;/* time_t tt = time(NULL);tm * pTime = localtime(&tt);int nYear = pTime ->tm_year+1900;int nMonth = pTime ->tm_mon+1;int nDay = pTime ->tm_mday;int nHour = pTime ->tm_hour;int nMin = pTime ->tm_min;int nSec = pTime ->tm_sec;char s[200];sprintf(s,"当前时间是:%d年%02d⽉%02d⽇ %02d:%02d:%02d",nYear,nMonth,nDay,nHour,nMin,nSec);MessageBox(NULL,s,"提⽰",0);*/return0;}MFC所有封装类⼀共200多个,但是MFC的内部技术不只是简单的封装。
深入浅出MFC一解析
深入浅出MFC一Contents[Trial version] 目录[Trial version] 第0章你一定要知道(导读)[Trial version] 第1章Win32基本程序观念[Trial version] 第2章C++的重要性质[Trial version] 第3章MFC六大关键技术之模拟[Trial version] 第5章总观AlicationFramework[Trial version] 第6章MFC程序设计导论[Trial version] 第7章简单而完整:MFC骨干程序[Trial version] 第8章Document-View深入探讨[Trial version] 第9章消息映射与命令绕行[Trial version] 第10章MFC与对话框[Trial version] 第11章View功能之加强与重绘效率之提升[Trial version] 第12章打印与预览[Trial version] 第13章多重文件与多重显示[Trial version] 第14章MFC多线程程序设计[Trial version] 第15章定制一个AWizard[Trial version] 第16章站上众人的肩膀--使用Comonents&am;amActiveXControls[Trial version] 附录A无责任书评[Amber demo]owered By Gisun htt://目录第0章你一定要知道(导读)/1这本书适合谁/1你需要什么技术基础/1你需要什么软硬件环境让我们使用同一种语言本书符号习惯/3磁盘内容与安装范例程序说明第一篇勿在浮砂筑高台- 本书技术前提/3 第1章Win32 程序基本观念/3Win32程序开发流程/4需要什么函数库(.LIB)/4需要什么头文件(.H)/4以消息为基础以事件驱动之/5一个具体而微的Win32 程序/5程序进入点WinMain/10窗口类之注册与窗口之诞生/11 消息循环/12窗口的生命中枢—窗口函数/12 消息映射(Message Ma)雏形/13 对话框的运作/14模块定义文件(.DEF)/14资源描述文件(.RC)/15 Windows 程序的生与死/15闲置时间的处理:OnIdle /16 Console 程序/17Console 程序与DOS 程序的差别/17 Console 程序的编译链接/18JBACKU:Win32 Console 程序设计/19 MFCCON:MFC Console 程序设计/20什么是C Runtime Library 的多线程版本/22 进程与线程(rocess and Thread)/22核心对象/22一个进程的诞生与死亡/23产生子进程/23一个线程的诞生与死亡/24以_beginthreadex取代CreateThread/25线程优先权(riority)/26多线程程序设计实例/27第2章C++ 的重要性质/29类及其成员—谈封装(encasulation)/29基类与派生类—谈继承(Inheritance)/29this 指针/31虚函数与多态(olymorhism)/32类与对象大解剖/40Object slicing 与虚函数/42静态成员(变量与函数)/44C++程序的生与死:兼谈构造函数与析构函数/46四种不同的对象生存方式/47所谓“Unwinding”/48运行时类型信息(RTTI)/48动态生成(Dynamic Creation)/50异常处理(Excetion Handling)/50 Temlate /53Temlate Functions /53Temlate Classes /54Temlates 的编译与链接/56第3章MFC六大关键技术之模拟/57MFC类阶层/57Frame1范例程序/57MFC程序的初始化过程/59Frame2范例程序/61RTTI(运行时类型辨识)/65 CRuntimeClass与类型录/65DECLARE_DYNAMIC / IMLEMENT_DYNAMIC宏/66 Frame3 范例程序/71IsKindOf(类型辨识)/77Frame4 范例程序/77Dynamic Creation(动态生成)/78DECLARE_DYNCREATE / IMLEMENT_DYNCREATE 宏/79 Frame6 范例程序/84ersistence(永续生存)机制/91Serialize(数据读写)/91DECLARE_SERIAL/IMLEMENT_SERIAL 宏/95没有范例程序Message Maing(消息映射)/97Frame7 范例程序/104Command Routing(命令循环)/112Frame8 范例程序/119本章回顾/130第二篇欲善工事先利其器-Visual C++ 5.0 开发工具第4章Visual C++ - 整合性软件开发环境安装与组成四个重要的工具内务府总管:Visual C++ 整合开发环境关于roject关于工具设定Source BrowserOnline Hel除错工具VC++ 除错器Excetion Handling程序代码产生器—AWizard东圈西点完成MFC 程序骨干Scribble Ste0威力强大的资源器Icon 器Cursor器Bitma器ToolBar器VERSIONINFO资源器String Table器Menu 器Accelerator 器Dialog 器Console 程序的项目管理第三篇浅出MFC程序设计第5章总观Alication Framework /130 什么是Alication Framework /130侯捷怎么说/130我怎么说/131别人怎么说/133为什么使用Alication Framework /134 Microsoft Foundation Class(MFC)/136 白头宫女话天宝:Visual C++与MFC/137 纵览MFC /138General urose classes /138Windows AI classes /139Alication framework classes /140High level abstractions /140Afx全局函数/140MFC宏(macros)/141MFC数据类型(data tye)/142第6章MFC程序设计导论——MFC程序的生死因果/144 不二法门:熟记MFC类的阶层架构/144需要什么函数库(.LIB)/146需要什么含入文件(.H)/146简化的MFC程序架构—以Hello MFC为例/148Hello 程序原始代码/148MFC 程序的来龙去脉/152我只借用两个类:CWinA和CFrameWnd /152 CWinA—取代WinMain的地位/152CFrameWnd—取代Wndroc的地位/154引爆器—Alication object /155隐晦不明的WinMain /156AfxWinInit - AFX 内部初始化动作/158CWinA::InitAlication /160CMyWinA::InitInstance /160CFrameWnd::Create 产生主窗口(并注册窗口类)/161 奇怪的窗口类名称Afx:b:14ae:6:3e8f/168 窗口显示与更新/170CWinA::Run - 程序生命的活水源头/170把消息与处理函数串接在一起:Message Ma机制/172来龙去脉总整理/173Callback 函数/174闲置时间(idle time)的处理:OnIdle/176 Dialog 与Control/178通用对话框(Common Controls)/178本章回顾/179第7章简单而完整:MFC 骨干程序/180 不二法门:熟记MFC 类的阶层架构/180 MFC程序的UI新风貌/180Document/View 支撑你的应用程序/181 利用Visual C++工具完成Scribble ste0 /183骨干程序使用哪些MFC类?/183Document Temlate的意义/187Scribble的Document/View 设计/190主窗口的诞生/192工具列和状态列的诞生(Toolbar &am; Status bar)/193 鼠标拖放(Drag and Dro)/195消息映射(Message Ma)/196标准菜单File/Edit/View/Window/Hel/196对话框/199改用CEditView /199第四篇深入MFC程序设计/199第8章Document-View 深入探讨/200为什么需要Document-View(形而上)/200 Document /200View /201Document Frame(View Frame)/202Document Temlate /202CDocTemlate 管理CDocument / CView / CFrameWnd /202 Scribble Ste1 的Document(数据结构设计)/207 MFC Collection Classes 的选用/207Temlate-Based Classes /208Temlate-Based Classes 的使用方法/209CScribbleDoc 的修改/209 SCRIBBLEDOC.H /211 SCRIBBLEDOC.C /212文件:一连串的线条/215 CScribbleDoc 的成员变量/215 CObList /215CScribbleDoc 的成员函数/215 线条与坐标点/217CStroke 的成员变量/217 CArray<Coint, Coint> /217 CStroke 的成员函数/217Scribble Ste1 的View:数据重绘与/218 CScribbleView 的修改/218 SCRIBBLEVIEW.H /219SCRIBBLEVIEW.C /220View 的重绘动作—GetDocument和OnDraw /222 CScribbleView的成员变量/222 CScribbleView的成员函数/223View 与使用者的交谈(鼠标消息处理实例)/223 ClassWizard 的辅佐/224WizardBar 的辅佐/225Serialize:对象的文件读写/225Serialization以外的文件读写动作/226 台面上的Serialize动作/227台面下的Serialize写文件奥秘/231台面下的Serialize读文件奥秘/233 DYNAMIC / DYNCREATE / SERIAL 三宏/240 Serializable 的必要条件/244CObject 类/245IsKindOf/245IsSerializable/245CObject::Serialize/245CArchive类/246oerator<<和oerator>>/246效率考虑/250自定SERIAL宏给抽象类使用/250在CObList中加入CStroke 以外的类/250 Document与View 交流—为Scribble Ste4做准备/254 第9章消息映射与命令循环/255到底要解决什么/255消息分类/256万流归宗Command Target(CCmdTarget)/256三个奇怪的宏一张巨大的/257 DECLARE_MESSAGE_MA 宏/257消息映射的形成:BEGIN_/ON_/END_ 宏/258米诺托斯(Minotauros)与西修斯(Theseus)/261 两万五千里长征—消息的流窜/265直线上溯(一般Windows 消息)/265拐弯上溯(WM_COMMAND 命令消息)/268罗塞达碑石:AfxSig_xx 的秘密/273Scribble Ste2:UI 对象的变化/277改变菜单/277改变工具列/278利用ClassWizard连接命令项识别代码与命令处理函数/280 维护UI对象状态(UDATE_COMMAND_UI)/282本章回顾/285第10章MFC 与对话框/285对话框器/286利用ClassWizard 连接对话框与其专属类/288ENDLG.H /290ENDLG.C /291对话框的消息处理函数/292MFC中各式各样的MA /294对话框数据交换与查核(DDX &am; DDV)/294MFC中各式各样的DDx_函数/297如何唤起对话框/297本章回顾/299第11章View功能之加强与重绘效率之提升/299同时修改多个Views:UdateAllViews 和OnUdate/300 在View中定义一个hint/302把hint传给OnUdate/304利用hint增加重绘效率/305可卷动的窗口:CScrollView /307大窗口中的小窗口:Slitter /313分裂窗口的功能/313分裂窗口的程序概念/314分裂窗口之实现/315本章回顾/317第12章印表与预览/317概观/317打印动作的后台原理/320MFC预设的打印机制/324Scribble打印机制的补强/333打印机的页和文件的页/333配置GDI绘图工具/334尺寸与方向:关于映射模式(坐标系统)/334分页/336表头(Header)与表尾/338动态计算页代码/338打印预览(rint review)/339本章回顾/339第13章多重文件与多重显示/339 MDI 和SDI /340多重显像(Multile Views)/340窗口的动态分裂/342窗口的静态分裂/343 CreateStatic 和CreateView /343窗口的静态三叉分裂/345Grah 范例程序/346静态分裂窗口之观念整理/354同源子窗口/355 CMDIFrameWnd::OnWindowNew/355 Text 范例程序/356非制式作法的缺点/361多重文件/361新的Document类/362新的Document Temlate /363新的UI系统/364新文件的文件读写动作/365第14章MFC多线程程序设计(Multi-threaded rogramming in MFC)/367从操作系统层面看线程/367三个观念:模块、进程、线程/367线程优先权(riority)/368线程排程(Scheduling)/369Thread Context /370从程序设计层面看线程/371Worker Threads 和UI Threads /371错误观念/372正确态度/372MFC多线程程序设计/372探索CwinThread/372产生一个Worker Thread/374产生一个UI Thread /375线程的结束/376线程与同步控制/376 MFC多线程程序实例/378第15章定制一个AWizard /380到底Wizard是什么?/381Custom AWizard 的基本操作/381剖析AWizard Comonents /385Dialog Temlates 和Dialog Classes /385Macros /386Directives /387动手修改To Studio AWizard/387利用资源器修改IDD_CUSTOM1对话窗画面/387 利用ClassWizard 修改CCustom1Dlg类/388改写OnDismiss 虚函数在其中定义macros /389 修改text temlate/389To Studio AWizard执行结果/390更多的信息/390第16章站上众人的肩膀—使用Comonents和ActiveX Controls/391 什么是Comonent Gallery /391使用Comonents /393Slash screen /393System Info for About Dlg /394Tis of the Day /394Comonents实际运用:ComTest 程序/395修改ComTest 程序内容/409使用ActiveX Controls /411ActiveX Control 基础观念:roerties、Methods、Events/411ActiveX Controls 的五大使用步骤/412使用“Grid”ActiveX Control:OcxTest 程序/413[Amber demo]owered By Gisun htt://第0章你一定要知道(导读)这本书适合谁深入浅出MFC是一本介绍MFC(Microsoft Foundation Classes)程序设计技术的书籍。
VCMFC学习笔记六:几个小知识(I)--全域函数,数据类型,CWnd和HWnd等
VCMFC学习笔记六:几个小知识(I)--全域函数,数据类型,CWnd和HWnd等1.常见的Afx全域函数AfxWinInit 被WinMain调用的一个函数,用做MFC GUI 程序初始化的一部份AfxBeginThread 开始一个新的执行线程AfxEndThread 结束一个旧的执行线程AfxMessageBox 类似Windows API 函数MessageBoxAfxGetApp 取得application object(CWinApp衍生对象)的指针AfxGetMainWnd 取得程序主窗口的指针AfxGetInstance 取得程序的instance handleAfxRegisterClass 以自定的WNDCLASS 注册窗口类别MFC独特的数据类型3. CWnd和HWndHWND是Windows系统中对所有窗口的一种标识,即窗口句柄。
这是一个SDK概念。
CWnd是MFC类库中所有窗口类的基类。
微软在MFC中将所有窗口的通用操作都封装到了这个类中,如:ShowWindow等等,同时它也封装了窗口句柄即m_hWnd成员。
由HWnd得到CWnd*:CWnd wnd;HWnd hWnd;wnd.Attach(hWnd);通常一个窗口资源已经和一个CWnd类的对象关联起来的,由于一般来说这个类是自己创建的,所以自然知道怎么得到指向这个类的指针。
由CWnd获取HWnd就容易多了,因为它的一个成员m_hWnd就是所对应窗口的句柄。
wnd->m_hWnd;这里再提一下封装的概念:MFC是对Windows API的封装,使用OOP是对Windows编程的另外一种观点。
MFC认为一个程序是一个对象(CWinApp),该对象管理窗口(CView或CDialog和CFrameWnd)以及该程序所使用的数据(CDocument)。
CWnd是CView和CDialog的父类,主要负责管理程序生成的窗口。
MFC 教程 第3章 MFC基础
重写CWinApp派生类的虚函数InitInstance。在 这个函数中,按自己的需要创建和显示窗口。 在CDocument的派生类中,声明程序所需的数 据和对这些数据进行必要操作的接口函数。 在CView类的派生类中编写处理消息的代码。 如果在消息处理中需要文档中的数据,则应该 调用该类的成员函数GetDocument来获取文档 对象,然后通过文档对象的接口函数对文档中 的数据进行操作。 在CView类的派生类中的OnDraw函数中编写窗 口重绘时的代码。 用宏实现类的消息映射表 23
3.4 对象的动态创建
在MFC应用程序中,类的对象一般都是动 态创建的.通过从文件中获得某个类的信 息之后,利用这些信息恢复或创建该类的 对象.因此,需要一个结构,专门存储这个类 的相关信息.
24
类信息表: struct CRuntimeClass { LPCSTR m_lpszClassName; …… CRuntimeClass* m_pBaseClass; CRuntimeClass* m_pNextClass; };
13
3.3.1 文档\视图类的基本概念
在文档\视图结构的框架中, 视图类CView类的对象用来显示数据并接受 用户操作, 框架窗口类CFrameWnd是视图类对象的容器。 文档类对象在幕后存储和管理数据,因此文 档类对象在程序界面上看不到。
14
3.3.2 文档类CDocument
文档类CDocument对象存储和管理应用程 序的数据。
25
与处理消息映射类似,MFC把在类中声明 类信息表的代码封装在宏 DECLARE_DYNCREATE中,而把实现类信 息表和链表的代码封装在了宏 IMPLEMENT_DYNCREATE中.因此,凡是 设计具有动态创建对象能力的类时,都要 使用这两个宏.
MFC六大核心机制
MFC六⼤核⼼机制MFC六⼤核⼼机制概述我们选择了C++,主要是因为它够艺术、够⾃由,使⽤它我们可以实现各种想法,⽽MFC将多种可灵活使⽤的功能封装起来,我们岂能忍受这种“⿊盒”操作?于是研究分析MFC的核⼼机制成为必然。
⾸先,列出要讲的MFC六⼤核⼼机制:1、MFC程序的初始化。
2、运⾏时类型识别(RTTI)。
3、动态创建。
4、永久保存。
5、消息映射。
6、消息传递。
本⽂讲第⼀部分,MFC程序的初始化过程。
简单的MFC窗⼝程序设计⼀个简单完整MFC程序,产⽣⼀个窗⼝。
当然这不能让AppWizard⾃动为我们⽣成。
我们可以在Win32 Application⼯程下⾯那样写:C++代码1 #include <afxwin.h>2class MyApp : public CWinApp3 {4public:5 BOOL InitInstance() //②程序⼊点6 {7 CFrameWnd *Frame=new CFrameWnd();//构造框架8 m_pMainWnd=Frame; //将m_pMainWnd设定为Frame;9 Frame->Create(NULL,"最简单的窗⼝");//建⽴框架10 Frame->ShowWindow(SW_SHOW); //显⽰框架11return true; //返回12 }13 };14 MyApp theApp; //①建⽴应⽤程序。
View Code设定链接MFC库,运⾏,即可看见⼀个窗⼝。
从上⾯,⼤家可以看到建⽴⼀个MFC窗⼝很容易,只⽤两步:⼀是从CWinApp派⽣⼀个应⽤程序类(这⾥是MyApp),然后建⽴应⽤程序对象(theApp),就可以产⽣⼀个⾃⼰需要的窗⼝(即需要什么样就在InitInstance()⾥创建就⾏了)。
整个程序,就改写⼀个InitInstance()函数,创建那么⼀个对象(theApp),就是⼀个完整的窗⼝程序。
MFC原理第四讲.动态创建机制
MFC原理第四讲.动态创建机制 MFC原理第四讲.动态创建机制⼀⼂要学习的知识点以及简介 动态创建是什么意思? 动态创建其实就是跟C++的new⼀样.都是创建对象.但是规避了C++语法的缺陷.例如: char * ClassName = "CMyApp" CObject *obj = new ClassName;C++ 中不允许这样编写代码要学习的知识点 1.DECLARE_DYNCREATE 宏学过上讲RTTI的应该明⽩.这个就是个⽂字替换. 也可以说这个宏是⼀个声明宏当然也有实现宏 2.IMPLEMENT_DYNCREATE还需要了解CRuntimeClass 结构. ⽀持动态创建的成员.struct CRuntimeClass{LPCSTR m_lpszClassName; 类名int m_nObjectSize; 类⼤⼩UINT m_wSchema; 类编号CObject* (PASCAL* m_pfnCreateObject)(); 存放⽀持动态创建的类CRuntimeClass* m_pBaseClass;// OperationsCObject* CreateObject(); 动态创建函数BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const; 判断函数...CRuntimeClass* m_pNextClass; 链表存储执向下⼀个};⼆⼂如何使⽤动态创建. ⽀持动态创建的是跟窗⼝有关的. 也就是CFrameWnd类. 如果我们继承了这个类.我们也可以让他⽀持动态创建. 1.添加声明宏 2.添加实现宏 3.动态创建使⽤.添加声明宏则添加到我们继承CFrameWnd类中即可. 实现宏则在外边参数填写⾃⼰的类名添加实现宏使⽤动态创建. 在InitInstance⾥⾯使⽤即可.我们的new 窗⼝改成动态创建即可.RUNTIME_CLASS宏可以拆解开.m_pMainWnd = (CMainWnd *)((CRuntimeClass*)(&CMainWnd::classCMainWnd))->CreateObject();应⽤程序实现截图:三⼂动态创建实现原理之宏拆开 我们要看实现原理.当然要把宏拆看看看做了什么事情了.1. DECLARE_DYNCREATE 宏拆开#define DECLARE_DYNCREATE(class_name) \DECLARE_DYNAMIC(class_name) \ RTTI动态识别static CObject* PASCAL CreateObject();我们可以看到这个宏包含了我们的RTTI 类型识别. 并且添加了⼀个新的成员函数static Cobject * Createobject();RTTI动态识别.上⼀讲已将讲过了. 就是添加了⼀个 CRuntimeClass 成员.以及获取成员的⽅法. 本次不讲解. 全部解开的宏public:static const CRuntimeClass classCMainWnd; 指针virtual CRuntimeClass* GetRuntimeClass() const; 获取这个指针的函数static CObject* PASCAL CreateObject(); 新增的函数2.实现宏拆开 IMPLEMENT_DYNCREATE#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \CObject* PASCAL class_name::CreateObject() \{ return new class_name; } \IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \class_name::CreateObject, NULL)其中还包含了⼀个宏 IMPLEMENT_RUNTIMECLASS也进⾏拆开.#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \#class_name, sizeof(class class_name), wSchema, pfnNew, \RUNTIME_CLASS(base_class_name), NULL, class_init }; \CRuntimeClass* class_name::GetRuntimeClass() const \{ return RUNTIME_CLASS(class_name); }第⼀个宏 IMPLEMENT_DYNCREATE 其实就是对 CreateObject进⾏实现. 也就是返回⾃⼰本⾝的创建的类第⼆个宏就是对⾃⼰本⾝的结构体成员进⾏初始化.并且实现虚函数获取⾃⼰的这个成员. 跟RTTI⼀样.只不过初始化的时候.结构体初始化的值不⼀样.也就是我们上⾯说的CRuntimeClass结构中的新增的两个成员进⾏了赋值.解析的代码//IMPLEMENT_DYNCREATE(CMainWnd,CFrameWnd)CObject* PASCAL CMainWnd::CreateObject(){return new CMainWnd;}const CRuntimeClass CMainWnd::classCMainWnd ={"CMainWnd", sizeof(class CMainWnd), 0xFFFF, CMainWnd::CreateObject, 添加了⾃⼰的成员函数指针.其余地⽅⼀样这个函数指针创建⾃⼰本⾝对象并且返回.RUNTIME_CLASS(CFrameWnd), NULL, NULL};CRuntimeClass* CMainWnd::GetRuntimeClass() const{return RUNTIME_CLASS(CMainWnd);}所以远离就是CRuntime⾥⾯添加⾃⼰创建对象的函数指针. 然后⾃⼰的类中实现这个函数.创建⾃⼰的对象并且返回这个就是动态创建了.。
MFC笔记
GetDlgItem:根据ID获取一个子窗口的对象地址(包含窗口句柄) GetDlgItemText和SetDlgItemText:根据ID获取或设置一个子窗口标题文字 GetDlgItemInt和SetDlgItemInt:根据ID获取或设置一个子窗口内显示的数字 GetDlgCtrlID和SetDlgCtrlID:根据窗口对象内的句柄获取或设置该窗口的ID GetParent和IsChild:这两个函数是等价的 GetWIndow: GetNextWIndow:
InitDialog函数用于初始化对话框中的子控件,可操作子窗口 Create函数主要用于 通用窗口的创建函数,如菜单、工具条等,窗口还未显示出来, 只有父窗口,子窗口还没创建 在非模式对话框中: 在使用EndDialog函数关闭时,只有隐藏没有真正关闭 使用DestroyWindow函数进行真正关闭
3—4讲,24分18秒
系统消息和非系统消息
• 系统消息编号:1—WM_USER-1 • 非系统消息:消息编号要大于1024,主要 用于传递数据
SendMessage函数和PostMessage函数的区别: 二者的功能: 能够向指定的窗口发送窗口消息,既可以是本进程内窗口 也可以是其它进程的 可以发送系统和非系统消息 SendMessage是阻塞型函数,用于调用指定窗口的内部程序,直到窗口 程序处理完毕后再返回 是非阻塞型函数,是将一个消息寄送到指定窗口内的消息 队列后立即返回
步骤如下: 1.定义自己的消息宏,如UM_ADD等,消息编号必须是大于 WM_USER,因为从1到WM_USER是系统消息; 2.自动添加消息处理函数 3.将“自定义的消息宏”和“消息处理函数”绑定,利用ON_ MESSAGE宏实现; 4.添加自己的代码,实现具体的功能
深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:命令传递)
软件英才网软件行业驰名招聘网站命令传递(Command routing)消息如果是仅仅从派生类流向父类,那就非常简单了。
然而MFC用来处理消息的C++类,并不是单线发展的。
document/view也具有处理消息的能力。
因此,消息应该有横向流动的机会。
MFC对消息循环的规定为:1:若是一般的windows消息(WM_xx)则一定是由派生类流向基类。
2:如果是WM_COMMAND消息,就非常复杂了。
要区分接受者的类型:1:接受者若为Frame窗口:处理次序为:View-> Frame窗口本身->CWinApp类。
2:接受者若为View :处理次序为:View本身->Document;3:接受者若为Document:处理次序为:Document本身->Document template软件英才网软件行业驰名招聘网站因此,接下来我们的任务就是仿真以上的消息传递路线。
以下为需要添加的函数:全局函数AfxWndProc,它是整个消息循环的起始点,本来应该在CWinThread::Run中被调用,每调用一次就推送一个消息。
模拟windows的disPatch函数。
软件英才网软件行业驰名招聘网站LRESULT AfxWndPro(HWND hWnd,UINT nMsg,WPARAMwParam,LPARAM lParam,CWnd *pWnd) {cout<<"AfxWndProc()"<<endl;return AfxCallWndProc (pWnd,hWnd,nMsg,wParam,lParam); }LRESULT AfxCallWndProc(CWnd*pWnd,HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM lParam)软件英才网软件行业驰名招聘网站{cout<<"AfxCallWndProc"<<endl;LRESULT lResult=pWnd->windowProc(nMsg,wParam,lParam);return lResult;}全局函数AfxCallWndProc用于调用接受消息的类的消息处理函数。
MFC编程学习心得
//1、将C语言变量简单重新定义UINT、INT(32位,4字节)LONG、DWORD(32位,4字节)WPARAM、LPARAM(32位,4字节)SHORT、WORD(16位,2字节)LONG、LRESULTBOOL(TRUE、FALSE)PINTPSTR、LPSTR、LPCSTR(字符串指针,只读和可写)//2、H开头,Windows句柄类型变量HANDLE of Windows =>HWNDHANDLE of Instance =>HINSTANCEHANDLE of Icon =>HICON//3结构体类型SIZE、POINT、RECTMFC所有封装类一共有200多个,但是MFC的内部技术不只是简单地封装。
MFC内部总共有六大关键技术,构架起了整个MFC开发平台。
一、MFC的六大关键技术包括:a)MFC程序的初始化过程:b)消息映射机制;c)运行时类型识别(RTTI);d)动态创建;e)永久保存;f)消息传递;六大关键技术的目的是为了提高开发效率,开发者只需要在局部做简单的修改,即可处理大部分窗口事物。
二、SendMessage和PostMessage函数的功能:a)能够向指定的窗口内发送窗口消息,既可以是本进程内窗口也可以是其他进程的;b)既可以发送系统内部消息,消息编号的范围是:1-WM_USER-1;例如:WM_LBUTTONDONW,WM_MOUSEMOVE等;c)也可以发送非系统消息(开发者定义的消息),范围是WM_USER-0x7FFF。
三、SendMessage和PostMessage两个函数的区别是:a)SendMessage是阻塞型函数,PostMessage是非阻塞型函数:SendMessage用于调用指定窗口的内部程序,直到窗口程序处理完成以后再返回:PostMessage是将一个消息寄送到一个窗口内的消息队列后就立即返回。
b)两个函数的返回值不同:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM,lParam);BOOL PostMessage(HWND hWnd,UNIT Msg,WPARAM wParam,LPARAM,lParam); SendMessage的返回值依赖于消息处理函数c)跨线程或者跨进程发送消息,推荐使用PostMessage函数。
MFC原理系列报告之运行期类型识别
MFC原理系列报告之:运行期类型识别一总论刚学习完MFC,一时心血来潮,分析下MFC的几个关键技术,算是对学习的总结。
由于本人还是个初学者,能力有限,语言组织欠妥,肯定有不足之处,欢迎批评斧正。
有以下几个部分内容:1.RTTI(运行期类型识别)2.动态创建3.序列化的实现4.程序的产生,运行和结束,以单文档框架程序为例5.单文档框架程序/类型之间的关系6.MFC消息机制的流转7.实现自己的SPY ++二: RTTI, 动态创建,序列化RTTI是动态创建的基础,序列化同时用到动态创建和RTTI,所以RTTI 是MFC的基石。
三者的关系很紧密。
.1.动态创建可以简单理解为,通过字符串创建对象。
比如你封装了一个类CLine,如何仅仅通过字符串“CLine”创建来CLine类的对象。
2.序列化是指从持久存储介质中读出或写入一个对象的过程。
举个例子:在一个CAD系统里,用户画了一些线条呀,矩形等等。
如何将当前所有图形保存到文件中,下次打开文件,然后正确读取并显示出来。
让我们尝试分析下,假设有两个类CLine, CRectangle分别负责绘制线条和矩形。
CLine里保存线条的起始坐标点。
Crectangle保存矩形的左上角坐标点,以及右下角坐标点。
用户每画一个线条,则创建一个CLine对象,矩形也是如此。
当用户保存线条到文件时,需要保存哪些内容呢?肯定要有CLine的类型信息,类信息至少有类的名字。
如果不保存,读取图形文件时,无法创建一个CLine对象,也就不能再正确显示出来。
读出对象时,根据字符串“CLine”创建一个CLine对象,即动态创建。
这里保存和读取对象的过程就是序列化,很显然序列化需要动态创建的支持,但是二者共同基础却是RTTI。
三. RTTI详解RTTI (Run_Time Type Identification),即运行期类型识别,是MFC动态创建的基础,可以对类型进行管理,对类型之间的关系,对象的类型进行识别和检查。
MFC原理介绍
MFC原理介绍一:基础男瓜1、MFC封装了大部分的Windows API函数,由C格式的函数库升级为类库。
2、Windows程序开发由面向过程的开发模式晋升为面向对象的开发模式,从而使得Windows软件开发效率大大地提高了。
例如:要将两个字符串连接,在C语言中使用的是strcpy和strcat的函数,而CString类则使用“+”或“+=”符号操作即可。
对比MFC和Win32两个开发平台由此可见一斑。
3、MFC是面向对象开发,因此代码维护和修改的效率比Win32高很多。
比如说:MFC的程序代码一般是50个类,每个类有20个函数便于维护;而Win32程序的代码一共有1000个全局函数,函数没有分类使代码维护难度加大。
4、MFC开发平台还辅助了应用程序向导(MFC AppWizard)和类向导(ClassWizard)等工具,进一步的提高了Windows软件的开发效率。
二:MFC的六大关键技术MFC所有封装类一共200多个,但是MFC的内部技术不只是简单的封装。
MFC的内部总共有六大关键技术,架构起了整个MFC的开发平台。
MFC的六大关键技术包括:a)MFC程序的初始化过程;b)消息映射机制;c)运行时类型识别(RTTI);d)动态创建;e)永久保存;f)消息传递。
{六大关键技术的目的是为了提高开发效率,开发者只要在局部做简单地修改,即可处理大部分窗口事物。
}三:封装类的原理CTime 类的主要成员 函数原型 函数说明CTime( );缺省构造函数,构造一个无效时间对象CTime( const CTime& timeSrc ); 拷贝构造函数,从另一个对象复制时间CTime( time_t time );构造函数,从C 语言时间句柄构造时间CTime( int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec, int nDST = -1 ); 构造函数,通过年月日时分秒及毫秒构造时间 CTime( const SYSTEMTIME& sysTime, int nDST = -1 ); 从SYSTEMTIME 结构体对象构造时间 CTime( const FILETIME& fileTime, int nDST = -1 ); 从FILETIME 结构体对象构造时间 static CTime GetCurrentTime( ); 获取当前时间time_t GetTime( ) const; 从CTime 对象获取C 语言时间句柄 int GetYear( ) const; 获取年份 int GetMonth( ) const; 获取月份 int GetDay( ) const; 获取日期 int GetHour( ) const; 获取小时 int GetMinute( ) const; 获取分钟 int GetSecond( ) const; 获取秒 int GetDayOfWeek( ) const;获取星期运算符“==”、“!=”、“>”、“=”、“<>”、“>比较两个时间对象1、通过封装CTime 类我们可以认为,一个封装类往往有1个或一些核心的成员数据:a)CTime 中的time_t m_time;b)CSocket 类中的SOCKET m_hSocket; c)CRect 基类中的left,top,right,bottom; d)CWnd 中的HWND m_hWnd;几乎封装类所有的成员函数,都是围绕这个或这些核心的成员数据在工作的。
深入浅出MFC学习笔记(第三章MFC六大关键技术之仿真类
第三章:MFC六大关键技术之仿真:类型识别深入理解MFC的内部运行原理,是本次学习《深入浅出MFC》的主要目的。
要模仿的六大技术包括:1:MFC程序的初始化过程。
2:RTTI(Runtime type identification)运行时类型识别。
3:Dynamic creation 动态创建4:Persistence永久保存5:消息映射6:消息传递。
RTTI(运行时类型识别)IsKindOf能够侦测某个对象是否属于某种类。
即判断某一对象所属的类是否是父类或当前类;要达到动态类型识别的能力,必须在构建类继承体系时记录必要的信息,这被称为类型型录表。
MFC以链表的方式建立了此表。
类型型录表的每个元素为CRuntimeClass类型,其定义为:1class CRuntimeClass23{45public:67LPCSTR m_lpszClassName;//对象所属类名89 Int m_nObjectSize;//对象大小1011UINT m_wSchema;//模式号1213 CObject *(PASCAL*m_pfnCreateObject)();//构建函数抽象类为NULL1415 CRuntimeClass *pBaseClasss;//基类CRuntimeClass对象指针。
1617 Static CRuntimeClass *pFirstClass;//链表头指针。
1819 CRuntimeClass *m_pNextClass;//下一指针。
2021};MFC使用此类作为每个类的成员变量。
使用宏定义为每个类定义了自己的CRuntimeClass成员变量。
DECLAR_DYNAMIC和IMPLENMENT_DYNAMIC宏使用这两个宏将CRuntimeClass对象不知不觉放到类之中。
DECLARE_DYNMIC宏定义如下:22#define DELCARE_DYNMIC ( class_name ) \2324public:\2526static CRuntimeClass class##class_name \2728virtual CRuntimeClass *GetRuntimeClass()const;##用来告诉编译器把两个字符串连接起来。
追根究底剖析MFC六大关键技术收藏
追根究底,剖析MFC六大关键技术(第一部分)收藏追根究底,剖析MFC六大关键技术题外话:我并不认为MFC减轻了程序员们的负担,MFC出现的目的虽然似乎是为了让程序员不用懂得太多就可以进行视窗编程,但本人在MFC 里徘徊了很久很久(因为那时没有书本详细介绍MFC的原理),毫无收获。
可能朋友们会说,怎么一定要了解MFC的具体呢,“黑箱”作业不行吗?这不是微软的初衷吗?不行!!!如果这样,我宁愿永远不选择MFC!在学电脑之前,本人学习的东西大都与艺术不无关系,小学时参加过全国书画比赛获银奖。
儿时的爱好就是在一张纸上随心所欲地画画!MFC“黑箱”就象一幅硕大的抽象画(抽象到你不能理解),它用铅笔勾画好线条,然后请你填颜色。
我们怎么能忍受“黑箱”作业?我们选择C++,就是因为它够自由,够艺术,我们可以在此放飞幻想。
所以,我们要攻克MFC。
伟大孙老师在剖析MFC的时候虽然尽心尽力,但可能由于篇幅所限,说得并不大清楚(我相信许多学员都有这方面的感受)。
在此,我突发奇想,想与大家一同分享一下著名的MFC六大关键技术。
从什么地方开始讲起好呢?我觉得回到最初摸索MFC的时候,从基本谈起最好。
因为我知道,一个走过来程序员,总是忘记了当初自己是怎么走过来的,忘记了一个学员最想知道的是什么。
一个小小的问题(一两句话就可以解释的),足学以令手无寸铁的学员头大半个月,所以,我努力回忆当初是怎么让自己豁然开朗的。
转入正题:MFC的六大关键技术包括:MFC程序的初始化过程。
运行时类型识别(RTTI)。
动态创建。
永久保存。
消息映射。
消息传递。
MFC程序的初始化过程1、设计一个简单完整MFC程序,产生一个窗口。
当然这不能让AppWizard自动为我们生成。
我们可以在Win32 Application工程下面那样写:#include <afxwin.h>class MyApp : public CWinApp{public:BOOL InitInstance() //②程序入点{CFrameWnd *Frame=new CFrameWnd();//构造框架m_pMainWnd=Frame; //将m_pMainWnd设定为Frame;Frame->Create(NULL,"最简单的窗口");//建立框架Frame->ShowWindow(SW_SHOW); //显示框架return true; //返回}};MyApp theApp; //①建立应用程序。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
软件英才网软件行业驰名招聘网站第三章:MFC六大关键技术之仿真:类型识别深入理解MFC的内部运行原理,是本次学习《深入浅出MFC》的主要目的。
要模仿的六大技术包括:1:MFC程序的初始化过程。
2:RTTI(Runtime type identification)运行时类型识别。
3:Dynamic creation 动态创建4:Persistence永久保存5:消息映射6:消息传递。
RTTI(运行时类型识别)IsKindOf能够侦测某个对象是否属于某种类。
即判断某一对象所属的类是否是父类或当前类;要达到动态类型识别的能力,必须在构建类继承体系时记录必要的信息,这被称为类型型录表。
MFC以链表的方式建立了此表。
类型型录表的每个元素为CRuntimeClass类型,其定义为:1class CRuntimeClass23{45public:67LPCSTR m_lpszClassName;//对象所属类名89 Int m_nObjectSize;//对象大小10软件英才网软件行业驰名招聘网站11UINT m_wSchema;//模式号1213 CObject *(PASCAL*m_pfnCreateObject)();//构建函数抽象类为NULL1415 CRuntimeClass *pBaseClasss;//基类CRuntimeClass对象指针。
1617 Static CRuntimeClass *pFirstClass;//链表头指针。
1819 CRuntimeClass *m_pNextClass;//下一指针。
2021};MFC使用此类作为每个类的成员变量。
使用宏定义为每个类定义了自己的CRuntimeClass成员变量。
DECLAR_DYNAMIC和IMPLENMENT_DYNAMIC宏使用这两个宏将CRuntimeClass对象不知不觉放到类之中。
DECLARE_DYNMIC宏定义如下:22#define DELCARE_DYNMIC ( class_name ) \2324public:\2526static CRuntimeClass class##class_name \2728virtual CRuntimeClass *GetRuntimeClass()const;##用来告诉编译器把两个字符串连接起来。
如果使用这个宏:DELCARE_DYNMIC(CView);那么预编译器将生成下列代码:软件英才网软件行业驰名招聘网站29public:3031static CRuntimeClass classCView;3233virtual CRuntimeClass*GetRuntimeClass()const;以上代码仅仅是在类中定义CRuntimeClass对象,并定义一个返回CRuntimeClass对象地址的函数。
注意CRuntimeClass是static的,也就是说同一种类继承体系的对象共享一个CRuntimeClass对象。
初始化对象的内容以及建立类型型录表需要使用IMPLEMENT_DYNMIC宏。
34#define IMPLEMENT_DYNMIC (class_name,base_class_name)\3536_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL);3738_IMPLEMENT_RUNTIMECLASS又是一个宏,它定义如下:3940#define _IMPLEMENT_RUNTIMECLASS(class_name,\4142 base_class_name,wSchema,pfnNew)\4344static char _lpsz##class_name[]=#class_name;\4546 CRuntimeClass class_name::class##class_name=\4748 { _lpsz##class_name,sizeof(class_name),\4950 wSchema,pfnNew,\5152 RUNTIME_CLASS(base_class_name),NULL\5354 };软件英才网软件行业驰名招聘网站5556static AFX_CLASSINIT _init##class_name \5758 ( & class_name::class##class_name);\5960 CRuntimeClass *class_name::GetRuntimeClass()const\6162 {\6364return &class_name::class##classname;\6566 }6768#define RUNTIME_CLASS(class_name)\6970 ( &class_name::class##class_name);AFX_CLASSINIT是一个类,看着跟宏定义似的,这样做很容易让人迷惑。
它用于将本节点连接到类型型录表,定义如下:71class AFX_CLASSINIT7273{7475public:7677 AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数7879 {8081 pNewClass->m_pNextClass=CRuntime::pFirstClass;8283 CRuntimeClass::pFirstClass =pNewClass;8485 }8687};软件英才网软件行业驰名招聘网站用法:88class CWnd:public CCmdTarget8990{9192public:9394 DECLARE_DYNAMIC(CWnd);959697};IMPLEMENT_DYNMIC(CWnd,CCmdTarget);代码展开后为;98class CWnd:public CCmdTarget99100{101102public:103104static CRuntimeClass classCView;105106virtual CRuntimeClass*GetRuntimeClass()const107108109110};111112113114static char _lpszCWnd[]="CWnd";软件英才网软件行业驰名招聘网站115116CRuntimeClass CWnd::classCWnd=117118{119120_lpszCView , sizeof(CWnd) , FFFF,NULL , &Wnd::classCWnd , NULL);121122};123124static AFX_CLASSINIT _init_CWnd(&CWnd::classCWnd);125126{127128 Return &CWnd::classCWnd;129130}定义宏的过程很复杂,但是一旦定义好之后,在使用时仅仅两句话就可以完成定义CRuntimeClass对象并且连接类型型录链表的工作。
CObject是所有类的基类,也是链表的头,此类应特别定义,不能在CObject内使用定义好的宏。
131class CObject132133{134135public:136137virtual CRuntimeClass*GetRuntimeClass()const;138139static CRuntimeClass classCObject;140141};142软件英才网软件行业驰名招聘网站143static char szCobject[]="CObject";144145struct CRuntimeClass CObject::classCObject=146147{148149 szCObject ,sizeof(CObject),0xFFFF,NULL,NULL,NULL150151};152153static AFX_CLASSINIT _init_CObject(&Cobject::classObject);154155CRuntimeClass *CObject::GetRuntimeClass()const156157{158159return &CObject::classCObject;160161}由于CRuntimeClass对象是static成员变量,因此需要在类外初始化。
如果忘记初始化将会报链接错误。
CRuntimeClass*CRuntimeClass::pFirstClass=NULL;建好了类类型路表,要实现IsKindOf功能很容易。
首先在CObject加上一个IsKindOf函数,于是所有继承自此类的类都具有类型识别的功能。
能够将某个CRuntimeClass对象与类类型型录中的元素进行比较。
如:162class CObject163164{165软件英才网软件行业驰名招聘网站166public:167168bool IsKindOf(const CRuntimeClass*pClass)const169170{171172 CRuntimeClass *pClassThis=GetRuntimeClass();173174while(pClassThis)175176 {177178if(pClassThis==pClass)179180return true;181182 pClassThis=pClassThis->m_pBaseClass;//沿着基类寻找。
183184 }185186return false;187188}189190};如果我们调用CWnd *cw=new CWnd;cw->IsKindOf(RUNTIME_CLASS(CFrameWnd));RUNTIME_CLASS实际就是&CFrameWnd::classCFrameWnd,它就是CFrameWnd的static的CRuntimeClass类型成员。
函数内利用GetRuntimeClass取得本类的CRuntimeClass对象的地址,即&CWnd::classCWnd,然后进行比较。
因为每一类型共用一个static的CRuntimeClass对象,因此属于同于类的CRuntimeClass对象的地址软件英才网软件行业驰名招聘网站相同。
动态创建每一类的构建函数可以记录在类型别录中,当获得一个类名称,通过查找类别型录表找出对应的元素,然后调用其构建函数产生新对象。