学习《深入浅出MFC》总结下

第5章     总观Application Framework

 

1、Application Framework:我们挖出别人早写好的一整套模块(如MFC和OWL)之中的一部分,给个引子(application object)使它们一一实例化动起来,并被允许修改其中某些零件使程序更符合私人需求,如是而已。An extended collection of classes that cooperate to support a complete application architecture or application model, providing more complete application development support than a simple set of class libraries.

 

2、Class Library:一组具备面向对象性质的类,它们使应用程序的某些功能实现起来容易一些,这些功能包括数值运算与数据结构、绘图、内存管理等,这些类可以一片一片毫无瓜葛地并入应用程序内

 

3、几个相关概念:OLE控件、OCX、ActiveX控件

 

4、浏览MFC,MFC类主要可分为几大群组:

General Purpose classes:提供字符串类、数据处理类、异常情况处理类、文件类。。。等

Windows API classes:用来封装Windows API,例如窗口类、对话框类、DC类。。。等

Application framework classes:组成应用程序骨干,即此组类,包括Document/View、消息泵、消息映射、消息传递、动态创建、文件读写等

High level abstractions:包括工具栏、状态栏、拆分窗口、滚动窗口等

Operation system extensions:包括OLE、ODBC、DAO、MAPI、WinSock、ISAPI等

 

5、CObject是万类之首,凡类派生自CObject,得以继承数个面向对象重要性质,包括RTTI(运行时类型识别)、Persistence(对象保存)、Dynamic Creation(动态创建)、Diagnostic(错误诊断)

 

6、常用的Afx全局函数:AfxWinInit、AfxBeginThread、 AfxEndThread、AfxFormatString1、AfxFormatString2、AfxMessageBox、 AfxOutputDebugString、AfxGetApp、AfxGetMainWnd、AfxGetInstance、 AfxRegisterClass

 

7、Serialization是指将对象内容写到文件中,或从文件中读出。如此一来,对象的生命就可以在程序结束之后还延续下去,而在程序重新激活之后,再被读入。这样的对象可说是“persistent”(永续存在)

 

8、POSITION是MFC的独特数据类型,表示collection集合对象中的元素位置,常使用于MFC collection classes

 

 

第6章     MFC程序的生死因果

 

1、MFC程序需要的库包括:C Runtime函数库(LIBC.LIB或MSVCRT.LIB)、Windows API函数库(GDI32.LIB、USER32.LIB和KERNEL32.LIB)和MFC函数库(即AFX函数库,MFC42.LIB)

 

2、MFC程序需要的头文件:stdafx.h,通常包含afxwin.h文件,该文件包含了所有的MFC类的声明,并且也包含了Windows API函数的声明windows.h

 

3、三个资源文件的内容:afxres.h包含标准的资源ID,如ID_FILE_NEW等;resource.h包含用户自定义的资源ID;*.rc资源描述文件,对所有资源的文字描述

 

4、afx_msg等价于一个空格符,无实际意义

 

5、回调函数可以是下面两种情况:全局函数或者static类成员函数(无this指针)

 

6、CWinApp取代了WinMain在SDK中的地位(即WinMain重要做的事情大多由CWinApp的成员函数完成),而CFrameWnd取代了WndProc在SDK中的地位

 

7、窗口的风格style除了一般的风格外,还可以设置扩充风格,但要使扩充风格生效,该窗口必须以::CreateWindowEx函数创建,而不是::CreateWindow函数

 

8、PreCreateWindow函数的作用是注册窗口类,修改cs的lpszClass,并提供修改cs的其他属性的机会,接下来马上就会调用::CreateWindow或者::CreateWindowEx创建窗口

 

9、OnIdle(LONG lCount)函数是用来处理空闲时间的,可以重载它

 

 

第7章     简单而完整:MFC骨干程序

 

1、Document是数据的体,View是数据的面。我们通过CDocument管理数 据,通过Collections Classes(MFC中的一组专门用来处理数据的集合类)处理实际的数据;我们通过CView负责数据的显示,通过CDC和CGdiObject实际绘 图。

 

2、使用者通过View看到Document,也通过View改变Document。View是Document对外显示的接口,但它并不能完全独立,它必须依存在一个所谓的Document Frame窗口内。

 

3、使用者对Document的任何编辑操作都必须通过Document Frame窗口,消息随后传到CView。

 

4、同一个资源ID可以对应着多种不同种类的资源,如一个资源ID可对应一个菜单、一个图标、一个字符串等。在框架窗口建立时,经常利用这个资源ID一次性将这些资源产生出来

 

5、支持Drag and Drop鼠标拖放功能和双击打开功能的三个函数:CWnd::DragAcceptFile、CWinApp::EnableShellOpen和CWinApp::RegisterShellFileType。

 

注:关于MFC程序的启动,这章又谈了一些。我在看这本书之前写过一篇启动过程的文章,比书上的过程要详细一些,找时间整理一下。

 

 

第8章     Document-View深入探讨

 

1、MFC中用四个类来管理和表达Document/View结构,这四个类是:CDocTemplate、CDocument、CView和CFrameWnd。它们之间的关系用下面的图清楚地显示出来:

我自己也总结了这四个类的定义情况,有空整理出来。

 

2、MFC中设计了很多Collection Class,用来批量处理数据集合。这个在C++中采用了STL来处理。不知道MFC对STL的支持怎么样,好像有些支持的不是很好。

 

3、关于Serialize的问题这一章花了很多篇幅,有一个疑问:CArchive类实际 上缺省已经有Operator<<和Operator>>的定义,在IMPLEMENT_SERIAL中重载了 Operator>>。和缺省的有一些不一样,但是为什么仅仅重载Operator>>,而不重载Operator< <呢?书中没有交代。原因应该是使用缺省的Operator<<就可以完成任务。

 

4、使用Serialize时,最后要调用CArchive::WriteObject和 CArchive::ReadObject函数,而这两个函数都要按照一定的格式来读或写类的信息,这样岂不是限定了文档的格式吗?如果要处理一些通用格 式的文档,就没有用处了。我觉得这样子很不好,以后不准备使用这项功能。

 

 

第9章     消息映射与命令传递

 

1、消息映射与命令传递是两个不同概念,消息映射是所有消息流通的基础,而命令传递是在消息映射的基础上,针对WM_COMMAND消息,设计的与一般WM_XXX消息不同的传递方式和路线。

 

2、MFC把消息分为三大类:

2.1   命令消息(WM_COMMAND):是使用者命令程序做某些操作,可能来自菜单或加速键或工具栏按钮。MFC程序主要靠菜单项的识别码(menu ID)来识别。凡是派生自CCmdTarget类的都有资格接受命令消息;

2.2   标准Windows消息:除WM_COMMAND以外的WM_XXX都算是这一类。任何派生自CWnd类的,都可接收此消息;

2.3   Control Notification消息:由控件产生,为的是通知其父窗口(通常是对话框)某种情况发生。这类消息也是以WM_COMMAND形式呈现,新的控件以WM_NOTIFY形式出现。

 

3、命令消息的奇特传递路线在第3章已经总结过。

 

 

第10章   MFC与对话框

 

这一章好像没什么好讲的

 

第11章   View功能的加强与重绘效率的提高

 

1、这里所谓的View功能的加强指的是当多个View同时指向一个Document时,如 果其中的一个View更新后,如何使得其他的View都得到更新。主要是通过一个函数来实现,即CDocument::UpdateAllViews,它 可以更新文档所对应的所有View。

 

2、这里所谓的重绘效率的提高是指在重新绘制View时,如何只绘制需要重绘的窗口部分,不 需要重绘的部分不进行绘制,这样就可以提高重绘效率。主要是通过函数CView::OnUpdate,这个函数是CView::OnDraw函数调用之前 调用的,可以在这里分析哪个部分需要重绘,并调用InvalidateRect函数来送出需重绘的区域参数。几个函数的调用顺序如下: CDocument::UpdateAllViews->CView::OnUpdate->CView::OnPaint->CView:: OnDraw。

 

3、这一章的其他部分还介绍了逻辑坐标和设备坐标的概念和相互转换,我从一开始学MFC的时候,就搞不清楚这些东西,现在还是搞不懂,看来需要找篇专门的文章看看了,否则绘图肯定成问题。

 

 

第12章   打印与预览

 

1、这一章看的是头晕眼花。打印功能怎么这么复杂?复杂之处在于三点:第一、过程确实复杂, 下图是用MFC打印涉及的可改写的虚拟函数及其大概的功能,可以看到过程复杂;第二、设计到CDC类,对这个类的认识不够;第三、涉及到坐标变换和映射方 式,对这个极其的不理解,怎么会搞得如此之复杂呢?其他的GUI toolkits也设计的这么复杂吗?

 

2、DC就是Device Context,在Windows中凡绘图操作之前一定要先获得一个DC。它可能代表全屏幕,也可能代表一个窗口,或一块内存,或打印机。。。,DC中有 许多绘图所需的元素,包括坐标系统(映射方式)、原点、绘图工具(笔、刷、颜色。。。)等等。它还连接到底层的输出装置驱动程序。由于DC,我们在程序中 对屏幕作画和对打印机作画的操作才有可能完全相同。

 

3、OnPaint和OnPrint的关系:

 

 

第13章   多重文件与多重视图

 

1、这一章主要讲述如何为一个文档(即一个Document类对象)产生多个视窗口,以及如 何产生多个文档和多个视窗。看起来很复杂,其实只要掌握了MFC程序是如何创建文档对象、框架窗口对象以及视窗口对象的,这些功能实在是很容易实现的。还 是多花些时间把前面的MFC的生死因果多看看,或者看我写的MFC程序的启动过程。

 

2、注意,文档类、框架窗口类和视窗类三者当中,只要有一个类不同,则就应该将它们包裹到不同的DocTemplate类当中。但是并不意味着不同的DocTemplate中的三个类都不同。

 

 

第14章   MFC多线程程序设计

 

1、首先搞清楚模块、进程和线程的概念及区别。

模块是指一段可执行的程序(包括EXE和DLL),其程序代码、数据、资源被加载到内存中, 由系统建置的一个数据结构来管理它,该数据结构称为Module Database(MDB)。本书中有该结构的信息表,其中就包括程序、数据、资源等数据段的地址DataDirectory;

 

进程是指一大堆拥有权(ownership)的集合。进程拥有地址空间(由memory context决定)、动态配置而来的内存、文件、线程和一系列的模块,操作系统也用一个数据结构来管理它,即Process Database(PDB),该结构中有一个MODREFlist,包含了进程要用到的所有模块列表。也包含一个TreadList,指向进程中的所有线 程;

 

线程主要表达模块中的程序代码的“执行事实”,系统也是以一个特定的数据结构Thread Database, TDB来记录线程的所有相关数据,包括线程局部存储空间(Thread Local Storage, TLS),消息队列,handle表格、地址空间(memory context)等等。在TDB中有一个pCurrentPriority表示线程的优先权,有一个MessageQueue表示线程的消息队列,有一个 ThreadContext表示线程的地址空间,有一个TLSArray表示线程的TLS。

 

2、Thread Context是构成线程的“后台”,指一组缓存器值(包括指令IP)。因为线程常会被暂停,所以必须将暂停之前一刻的状态统统记录下来,以备将来还可以恢复。

 

3、从MFC的角度看,把线程划分为和使用者界面无关的worker threads,以及和使用者界面(UI)有关的UI threads。对于线程的使用,比较好的做法是把所有UI操作都集中在主线程中,其他的“纯种运算工作”才考虑交给worker threads去做。

 

4、如果你的程序有许多事要忙,但是你还要随时保持注意某些外部事件(可能来自硬件或来自使用者),这时就适合使用多线程来帮忙。

 

5、产生一个worker thread的过程:先为线程准备一个线程函数,然后调用AfxBeginThread函数创建一个CWinThread,其中指定其线程函数,如下:

CWinThread * pThread = AfxBeginThread(ThreadFunc, &Param);

UINT ThreadFunc(LPVOID pParam)

{

}     //实际上就是用这个线程函数来代表一个线程,函数return,线程也就结束了。

注意:在AfxBeginThread中new了一个CWinThread对象,所以一定要注意delete它。

 

6、产生一个UI thread的过程:由于UI thread需要一个消息循环,所以,产生UI线程需要先从CWinThread派生一个类,这个类就可以继承CWinThread的消息循环,然后再调用AfxBeginThread创建该派生类对象,如下:

CWinThread * pThread = AfxBeginThread(RUNTIME_CLASS(CMyThread));

注意:在结束UI线程的时候一定要让其产生一个WM_QUIT消息来结束线程,或者调用AfxEndThread。同时别忘了delete该对象。

 

 

 

第15章   定制一个AppWizard

 

 

第16章   站上众人的肩膀-使用Components&ActiveX Controls

 

1、三种控件的形式:VB中的VBX(Visual Basic eXtension)、Delphi和C++ Builder的VCL(Visual Component Library)和Visual C++的OCX(OLE Control eXtention),也称为ActiveX控件

 

2、在VC的Component Gallery中包含两种组件:Components和ActiveX Controls。两者的区别是:Components是一些已写好的C++类,Gallery基本上只是对这些C++类做了一些封装,连同其他资源放在 一起成为一个包裹,当加入这些Components时,将得到整个程序代码。而ActiveX Controls组件本身是在.ocx文件中的,加入时,只会包含一些如何使用该控件的代码,控件本身的代码是不会加入到项目中的。

 

3、ActiveX Controls的基础观念包含:Properties、Methods和Events(所谓的PME)。Property相当于C++类的成员变量或数 据成员;Methods相当于C++类的成员函数;Event相当于Windows控件中的Notification(通知消息),如 BN_CLICKED。

 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值