上一页 1 ··· 29 30 31 32 33 34 35 36 37 ··· 61 下一页
  2011年5月9日
摘要: 在窗口消息处理方面,CWnd使用了窗口子类化和消息映射机制,关于消息映射的知识将在第9章详述,下面着重阐述CWnd是如何应用子类化处理窗口消息的。其实,在6.2节的示例中,CBaseWnd已经使用了与CWnd类似的子类化方法处理窗口消息。成员函数CBaseWnd::SubWindowClass()将窗口过程子类化为CBaseWnd::MyBaseWndProc(),在这个窗口过程中调用CBaseWnd::WindowProc()处理窗口消息。原始的窗口过程存入成员m_Super WndProc中,在默认处理中调用。CWnd在窗口建立之初,使用AfxWndProc()子类化窗口,在AfxWndP 阅读全文
posted @ 2011-05-09 18:11 carekee 阅读(927) 评论(0) 推荐(0) 编辑
摘要: 既然在Windows操作系统下编程,窗口操作应该是程序设计的主要任务,一切与用户的接口都由窗口体现。窗口类往往用来组织数据、封装数据、表示数据,所以窗口操作也是Windows编程的核心内容。前面对CWnd类以及它与Windows窗口的关系作了简要论述。下面将进一步阐明CWnd类是如何关联Windows窗口的,是如何封装WIN32窗口操作的。首先要脱离MFC,使用WIN32 API创建一个单窗口应用程序,然后模拟CWnd自己编写一个窗口封装类,最后对CWnd进行阐述。6.1 使用WIN32 API创建窗口下面使用WIN32 API创建一个只包含一个主窗口的小程序,主函数WinMain()创建主窗 阅读全文
posted @ 2011-05-09 18:10 carekee 阅读(1190) 评论(1) 推荐(0) 编辑
摘要: 视图是程序设计中使用率最高的窗口对象,它是用户的主要操作界面。因为它通常以某种形式表示文档数据,所以称之为视图。一个视图对象只关联一个文档对象;一个文档对象可以关联多个视图,每个视图对象以不同形式表示文档数据。然而,除了打印和打印预览外,视图类显得很简单。下面就从关联文档对象、绘制等几个方面进行阐述。7.2.1 关联文档对象前面已经提到,视图需要表示文档数据,所以文档对象与视图对象必须建立关联。这样,当文档数据发生变化时,它可以及时通知视图;当视图需要显示不同的文档数据时,它可以从文档对象中提取。在文档/视图框架程序中,文档对象总是在视图之前建立,而在视图的WM_CREATE消息处理函数中,建 阅读全文
posted @ 2011-05-09 18:09 carekee 阅读(1351) 评论(0) 推荐(0) 编辑
摘要: 对话框与普通窗口的区别仅在于,对话框是通过对话框模板建立起来的。只需要一个以模板为实参的创建命令,如CDialog::Create(),就可以完成对话框窗口及其子控件的创建工作,所有创建细节都由对话框模板来指示。而对于普通窗口,窗口及其包含的子控件必须逐一创建,而且要指定窗口风格等详细参数。对话框是最基本的可视化编程方法,一个应用程序往往包含众多的对话框资源模板和封装类,而普通窗体(包括框架窗体)却寥寥无几。但对话框的使用,只是方便了窗体和控件的创建过程,其本质与普通窗体无任何区别。下面并不准备陈述对话框的技术细节,只与读者讨论两个相关问题:一是模态对话框的消息循环,二是对话框的命令消息路由。 阅读全文
posted @ 2011-05-09 18:09 carekee 阅读(1687) 评论(0) 推荐(0) 编辑
摘要: 如果给对话框附加了一个菜单资源,进入ClassWizard向导,就能够发现,不仅该对话框能够映射该菜单命令,而且主框架窗口、视图、文档、应用类也可以。如果一个对话框(无论弹出和重叠,不分模态与非模态)的父窗口是主框架或视图,该对话框的菜单命令就可以在多个对象中处理,它的处理路由是:对话框→视图→文档对象→主框架→应用类。一旦命令消息被处理,将不再继续传递。由此可知,对话框的命令处理路由与主框架的命令处理路由非常接近,只是增加了一个最高的优先处理对象:对话框本身。不难推测,在对话框的命令消息处理函数CDialog::OnCmdMsg()中,首先搜寻对象本身的消息映射,如果没有找到相应的处理函数, 阅读全文
posted @ 2011-05-09 18:09 carekee 阅读(383) 评论(0) 推荐(0) 编辑
摘要: 以上对CWnd作了深入的探讨,但是还不够全面,相信在以后章节的学习中,读者会逐渐地把握这个重要的基类。承接以上内容,下面学习CWnd几个实用的派生类:CFrameWnd、CView、CDialog。7.1 CFrameWnd类CFrameWnd类往往用于创建应用程序的主窗口,因为它能很好地支持系统菜单和控制条(工具条、状态条等),为此定义了大量的成员函数和变量。在编写文档/视图结构的应用程序时,CFrameWnd作为主窗口管理视图和文档对象。视图对象和控制条都成为CFrameWnd的子窗口,它们分享客户区,其位置被CFrameWnd有效地排列。CFrameWnd直接支持单文档界面(SDI),对 阅读全文
posted @ 2011-05-09 18:08 carekee 阅读(2130) 评论(0) 推荐(0) 编辑
摘要: 既然窗口操作是Windows编程的核心内容,那么窗口基类CWnd在MFC类结构中的核心地位就无可争议了。它派生于CCmdTarget类,是最基本的GUI对象。我们在屏幕上看到的一切对象都与窗口有关,它们或者派生于CWnd,属继承关系,如对话框、工具栏、状态栏、子控件;或者被CWnd合成,属服务员与服务对象的关系,如图标、菜单、显示设备。窗口类CWnd与Windows操作系统管理是显示(或隐藏)给用户的,作为应用程序的一种表现形式的窗口是两个概念。前者通过一个窗口句柄操作后者,不同的操作被封装为不同的成员函数。而后者,操作系统为其开辟了一个内存区,存储一个数据结构,进行管理。后者包括窗口风格、窗 阅读全文
posted @ 2011-05-09 18:07 carekee 阅读(1414) 评论(0) 推荐(0) 编辑
摘要: 该类派生于CObject,它封装了MFC的消息映射机制,希望接收系统事件和窗口消息的类都从它派生,如CDocument和CWnd分支。此外,在系统繁忙,无法响应窗口消息时,鼠标光标应该显示为沙漏形等待状态,CCmdTarget类封装了3个成员函数完成该功能。封装COM的 IDispatch接口是它的另一项主要功能。IDispatch是COM的标准接口,不含指针操作的语言(如VB)以及描述性语言(如Web脚本语言和VBA)都通过该接口操作COM组件。CCmdTarget类以一种类似消息映射的机制提供IDispatch接口,所以使用MFC可以轻松地编写AUTOMATION客户程序和组件。关于消息映 阅读全文
posted @ 2011-05-09 18:06 carekee 阅读(748) 评论(0) 推荐(0) 编辑
摘要: 我们知道,Windows以事件驱动方式工作,每个WIN32应用程序都至少包含一个消息队列和一个消息泵。消息队列建立在操作系统提供的内存保留区中,消息泵不断搜寻消息队列,将取得的消息分发给应用程序的各个部分进行处理,这个过程叫做消息循环。基本消息循环如下://从队列中提取消息while(GetMessage(&msg,0,0,0)){//转换消息参数TranslateMesssage(&msg);//分发消息DispatchMessage(&msg);}Windows以线程封装消息循环,封装消息循环的线程叫做用户界面线程,即UI线程。该线程可以创建并撤销窗口。此外还有一种 阅读全文
posted @ 2011-05-09 18:06 carekee 阅读(1583) 评论(0) 推荐(0) 编辑
摘要: 现在,可以比较深入地对CWnd类的封装机制进行剖析了。在建立窗口句柄映射方面,CWnd使用了一个未公开的类CHandleMap进行管理。使用CWnd及派生类创建窗口时,建立了句柄映射,在窗口销毁时删除映射。一个在MFC内部创建的CHandleMap对象管理所有CWnd实例与窗口句柄的映射,该对象通过一个内部使用的全局函数afxMapHWND()创建并取得。6.3.1 使用操作映射的函数CHandleMap主要包括3个成员函数:SetPermanent()(建立映射)、RemoveHandle()(删除映射)、LookupPermanent()(在映射中查找与指定句柄对应的对象指针)。下面代码是 阅读全文
posted @ 2011-05-09 18:05 carekee 阅读(1511) 评论(0) 推荐(0) 编辑
摘要: CObject是“MFC类之母”,由它派生出庞大的类体系。CObject并不是对整个类体系进行语义抽象的结果,它只为所有派生类定义几种功能特性。由于这几项功能应用于MFC的大部分类中,成为MFC的普遍现象,有必要认真学习。下面就着重讨论这几项功能特性。5.1.1 支持类诊断CObject类定义了这样一个虚拟函数:public:virtual void CObject::AssertValid() const{ ASSERT(this != NULL);}派生类可以对它进行重载,通过当前对象的状态,诊断它的有效性。诊断条件根据需要而定。一般通过ASSERT宏进行诊断,这样当调试出错时,程序会在失 阅读全文
posted @ 2011-05-09 18:05 carekee 阅读(1749) 评论(1) 推荐(0) 编辑
摘要: 既然在Windows操作系统下编程,窗口操作应该是程序设计的主要任务,一切与用户的接口都由窗口体现。窗口类往往用来组织数据、封装数据、表示数据,所以窗口操作也是Windows编程的核心内容。前面对CWnd类以及它与Windows窗口的关系作了简要论述。下面将进一步阐明CWnd类是如何关联Windows窗口的,是如何封装WIN32窗口操作的。首先要脱离MFC,使用WIN32 API创建一个单窗口应用程序,然后模拟CWnd自己编写一个窗口封装类,最后对CWnd进行阐述。6.1 使用WIN32 API创建窗口下面使用WIN32 API创建一个只包含一个主窗口的小程序,主函数WinMain()创建主窗 阅读全文
posted @ 2011-05-09 18:03 carekee 阅读(1461) 评论(0) 推荐(0) 编辑
摘要: 为了更通俗地阐释CWnd类的封装机制,下面自己动手,模拟CWnd编写一个简单的窗口封装类,名为CBaseWnd,并使用这个类重新实现示例6.1的功能。6.2.1 实例代码示例6.2是实现代码,其中定义了3个类,说明如下:q CBaseWnd相当于CWnd的窗口基类,封装了窗口创建与销毁、窗口状态和风格操作、窗口消息处理等功能,其中的消息处理函数定义为虚拟函数。q CMainWnd类派生于CBaseWnd,用于创建应用程序主窗口,其中重载了几个消息处理虚函数,实现特定的消息处理。q CMapHWD类被CBaseWnd类合成,用于管理窗口句柄与窗口封装类的映射关系。CBaseWnd实例与Windo 阅读全文
posted @ 2011-05-09 18:03 carekee 阅读(1732) 评论(0) 推荐(0) 编辑
摘要: 在示例2.3中,基类CCustEdit定义了虚拟函数BuildValues()为子类提供重载的形式,而这个虚拟函数本身从来就没有执行过,也没有执行的必要。并且,由基类CCustEdit实例化的对象也没有什么应用价值。CCustEdit类白白浪费了资源。对于这种情况,可以将基类的虚拟函数定义为纯虚函数。纯虚拟函数没有函数体,专为派生类提供重载的形式。只要形象地将虚拟函数赋值为0,即定义了纯虚函数。例如:void virtual BuildValues(char * Statement)=0;定义了纯虚函数的类称为抽象基类。抽象基类节省了内存空间,但不能用来实例化对象。其派生类必须重载所有的纯虚函 阅读全文
posted @ 2011-05-09 18:02 carekee 阅读(454) 评论(0) 推荐(0) 编辑
摘要: MFC作为一个宠大的类库,包含深层的派生类和多个类分支。在整个CObject类家族中,以及在每个类分支中,基类都相应地定义了虚拟函数。至于定义虚拟函数的必要性,在2.4节中已经讨论很多,下面还是对MFC中定义或重载虚拟函数的情况简单例举。CObject类是MFC类库之母,它为其派生类提供的几项功能支持,多数是以虚拟函数的形式出现的。或者说,CObject类的作用就是为其派生类定义了若干完成某项功能的虚函数,供派生类重载,供类的使用者调用。从而,类的使用者(如调用其虚拟函数的外部函数)对于整个类体系而言,就是通用函数。CObject类定义了以下虚函数,分别提供类的诊断、类的连载、类的运行时信息等 阅读全文
posted @ 2011-05-09 18:02 carekee 阅读(548) 评论(0) 推荐(0) 编辑
摘要: 编写通用的功能模块,处理多种对象类型。关于这种用法,上面已经讨论许多,这里作简要总结。q 处理的多种对象应该有共性,可以封装在一个类家族中。这个类家族的理想结构是多向二层次的(如图2-4所示),或者是单向多层次的(如图2-5所示)。 图2-4 多向二层次类家族 图2-5 单向多层次类家族q 在基类中定义若干公共虚拟函数,派生类对其部分或全部重载,但重载的虚函数应该与基类的声明一致,即参数列表一致(当然可以省掉virtual关键字)。q 每个类都封装一种处理对象的数据集和操作集。其中,几个处理对象的共性部分封装在相对的基类中;每个处理对象的特性操作封装在重载的虚函数中。q 定义通用函数,其形参之 阅读全文
posted @ 2011-05-09 18:00 carekee 阅读(498) 评论(0) 推荐(0) 编辑
摘要: 讲到这里,也许读者对虚拟函数还不能有一个清晰的认识。下面就对虚拟函数的实现机制作简要介绍。2.3.1 类和对象的内存分配机制首先应该了解类及对象的内存分配机制。如果有类的定义如下:class CMem{public:CMem();public :int m_first;private:unsigned char m_second;public:fun1();};则对象CMem a, b;的内存分配如图2-1所示。由图2-1可知,同一个类的所有对象共享同一个成员函数的地址空间,而每个对象有独立的成员变量地址空间。也可以这样说,成员函数是类拥有的,成员变量是类的对象拥有的。图2-1 类及对象的内存 阅读全文
posted @ 2011-05-09 17:58 carekee 阅读(467) 评论(0) 推荐(0) 编辑
摘要: 在实际开发工作中,为提高代码的重用性,编写通用的功能模块,往往需要设计处理几种不同对象的通用程序,如示例2.1所示。 示例清单2.1#include "stdio.h"#include "stdlib.h"//定义函数指针类型DISPLAYINTEGER,指向返回值为void,参数列表为(const int)的函数typedef void( *DISPLAYINTEGER)(const int);//定义函数,将数字以十进制形式输出,该函数类型与DISPLAYINTEGER匹配void DisplayDecimal(const int Number){p 阅读全文
posted @ 2011-05-09 17:55 carekee 阅读(513) 评论(0) 推荐(0) 编辑
  2011年5月6日
摘要: 对C++代码而言,内存泄漏问题虽然有诸多方法避免,但实际代码编写的时候,或出于自信或出于复杂性的考虑,常常还会用到原始的operator new,这不可避免的会带来内存泄漏的可能,不久前本人因为违反了"可用于被多态继承的基类其析构函数应当有virtual修饰"的法则( 一不小心就忘了写virtual ^_^ ),导致了内存泄漏,因此我觉得出于安全考虑,在代码中加入内存泄漏检查机制还是很必要的,也因为这次的内存泄漏事件促使我写出这一篇文章.VC++中本身就有内存泄漏检查的机制,你可以在向导生成的支持MFC的工程中看到如下代码:#ifdef _DEBUG#define new 阅读全文
posted @ 2011-05-06 17:51 carekee 阅读(304) 评论(0) 推荐(0) 编辑
摘要: 如果OLE控件不存在的话,在 try { HRESULT hr; hr = ::CoInitializeEx( Null, COINIT_APARTMENTTHREADED ); if( FAILED(hr) ) _com_issue_error(hr); LabLE1: hr = m_lpAnimator.CreateInstance(CLSID_GifAnimator); if( FAILED(hr) ) _com_issue_error(hr); //如果控件没有注册,就会抛出异常 } catch( _com_error e ) { /////////////////////////// 阅读全文
posted @ 2011-05-06 17:46 carekee 阅读(567) 评论(0) 推荐(0) 编辑
上一页 1 ··· 29 30 31 32 33 34 35 36 37 ··· 61 下一页