文档库 最新最全的文档下载
当前位置:文档库 › MFC CCmdTarget 介绍

MFC CCmdTarget 介绍

MFC CCmdTarget 介绍
MFC CCmdTarget 介绍

CCmdTarget

类CCmdTarget是MFC类库中消息映射体系的一个基类。消息映射把命令或消息引导给用户为之编写的响应函数(命令是由菜单项、命令按钮或者加速键产生的消息)。从CCmdTarget继承来的按键框架类包括:CView、CWinApp、CDocument、CWnd和CFrameWnd。如果想生成一个处理按键消息的类,可以选择其中的一个派生一个子类。很少需要直接从CCmdTarget派生类。

CCmdTarget类是MFC处理命令消息的基础、核心。MFC为该类设计了许多成员函数和一些成员数据,基本上是为了解决消息映射问题的,而且,很大一部分是针对OLE设计的。在OLE应用中,CCmdTarget是MFC处理模块状态的重要环节,它起到了传递模块状态的作用:其构造函数获取当前模块状态,并保存在成员变量

m_pModuleState里头。

CCmdTarget有两个与消息映射有密切关系的成员函数:DispatchCmdMsg和OnCmdMsg。

类CmdTarget包括了处理沙漏形光标显示的成员函数。当某个命令的执行时间比较长时,可以显示沙漏标提示用户命令正在执行。

和消息映射类似,分派映射用于列出OLE自动的IDispatch功能。列出这个接口后,其它的应用(如VB)就能调用这个应用了。有关IDispatch接口的更详细的信息,请参阅“Win32 SDK OLE程序员参考”中的“创建IDPatch接口”和“分派接口与API函数”。

所需头文件:#include

静态成员函数DispatchCmdMsg

CCmdTarget的静态成员函数DispatchCmdMsg,用来分发Windows消息。此函数是MFC内部使用的,其原型如下:

static BOOL DispatchCmdMsg(

CCmdTarget* pTarget,

UINT nID,

int nCode,

AFX_PMSG pfn,

void* pExtra,

UINT nSig,

AFX_CMDHANDLERINFO* pHandlerInfo)

虚拟函数OnCmdMsg

CCmdTarget的虚拟函数OnCmdMsg,用来传递和发送消息、更新用户界面对象的状态,其原型如下:

OnCmdMsg(

UINT nID,

int nCode,

void* pExtra,

AFX_CMDHANDLERINFO* pHandlerInfo)

框架的命令消息传递机制主要是通过该函数来实现的。

命令目标指希望或者可能处理消息的对象;命令目标类指命令目标的类。

CCmdTarget对OnCmdMsg的默认实现:在当前命令目标(this所指)的类和基类的消息映射数组里搜索指定命令消息的消息处理函数(标准Windows消息不会送到这里处理)。

这里使用虚拟函数GetMessageMap得到命令目标类的消息映射入口数组

_messageEntries,然后在数组里匹配指定的消息映射条目。匹配标准:命令消息ID 相同,控制通知代码相同。因为GetMessageMap是虚拟函数,所以可以确认当前命令目标的确切类。

如果找到了一个匹配的消息映射条目,则使用DispachCmdMsg调用这个处理函数;

如果没有找到,则使用_GetBaseMessageMap得到基类的消息映射数组,查找,直到找到或搜寻了所有的基类(到CCmdTarget)为止;

如果最后没有找到,则返回FASLE。

每个从CCmdTarget派生的命令目标类都可以覆盖OnCmdMsg,利用它来确定是否可以处理某条命令,如果不能,就通过调用下一命令目标的OnCmdMsg,把该命令送给下一个命令目标处理。通常,派生类覆盖OnCmdMsg时,要调用基类的被覆盖的OnCmdMsg。

在MFC框架中,一些MFC命令目标类覆盖了OnCmdMsg,如框架窗口类覆盖了该函数,实现了MFC的标准命令消息发送路径。

必要的话,应用程序也可以覆盖OnCmdMsg,改变一个或多个类中的发送规定,实现与标准框架发送规定不同的发送路径。例如,在以下情况可以作这样的处理:在要打断发送顺序的类中把命令传给一个非MFC默认对象;在新的非默认对象中或在可能要传出命令的命令目标中。

该类派生于CObject,经封装了MFC的消息映射机制,希望接收系统事件和窗口消息的类都从它派生,如CDocument和CWnd分支。此外,在系统繁忙,无法响应窗口消息时,鼠标光标应该显示为沙漏等待状态,CCmdTarget类封装了3个成员函数完成该功能。封装COM的IDispatch接口是它的另一项主要功能。IDispatch是COM的标准接口,不含指针操作的语言(如VB)以及描述性语言(如Web脚本语言和VBA)都通过该接口操作COM组件。CCmdTarget类以一种类似消息映射的机制提供IDispatch接口,所以使用MFC可以轻松地编写AUTOMATION客户程序和组件。

CCmdTarget类定义BeginWaitCursor()、EndWaitCursor()和RestoreWaitCursor()3个成员函数处理等待光标。BeginWaitCursor()将光标设置为沙漏形状,该函数有可能被程序框架调用,通知用户状态忙,例如当加载和存储文档时。EndWaitCursor()将光标恢复为沙漏之前的形状,一般与BeginWaitCursor()配合使用。

在实际编程中,在一个比较耗费机时的处理前应该主动调用BeginWaitCursor()设置光标,在处理结束时要调用EndWaitCursor()恢复光标。例如:

void CWaitCursorDoc::LoadFile(char * Filepath)

{

//显示沙漏光标

BeginWaitCursor();

//耗费机时的处理过程

TRACE("正在装入文件,请等待...\n");

......

//恢复为沙漏前的光标形状

EndWaitCursor();

}

如果在BeginWaitCursor()和EndWaitCursor()之间的处理中,弹出了模式对话框,光标会由沙漏变为标准形状(通常是标准箭头)。为处理这种情形,可以在对话框关闭后,调用成员RestoreWaitCursor()重新将光标设置回沙漏形状,直到处理结束后调用EndWait Cursor()。例如:

void CWaitCursorDoc::LoadFile(char * Filepath)

{

WIN32_FIND_DATA FindData;

//显示沙漏光标

BeginWaitCursor();

//耗费机时的处理过程

if(::FindFirstFile(Filepath,&FindData)==INVALID_HANDLE_VALUE)

{

TRACE("打开文件出错,请重新指定文件\n");

CFileDlg dlg;

dlg.DoModal();

//恢复光标的沙漏形状

RestoreWaitCursor();

}

TRACE("正在装入文件,请等待...\n");

......

//恢复沙漏前的光标形状

EndWaitCursor();

}

但如果弹出的是MessageBox()消息框,就不必调用RestoreWaitCursor(),光标会自动恢复为沙漏。

在非CCmdTarget派生类中,可以使用CWaitCursor类设置等待光标。该类的构造函数和析构函数相当于CCmdTarget::BeginWaitCursor()和CCmdTarget::EndWaitCursor(),成员函数Restore()相当于CCmdTarget:: RestoreWaitCursor()

CCmdTarget派生类设计及消息响应的实现CCmdTarget是微软基础类库消息映射体系中的基类。消息映射安排命令或消息到你编写的成员函数来处理它们,其中命令是来自菜单项、命令按钮或快捷键的消息。在实际应用中,继承自CCmdTarget的类包括CView, CWinApp, CDocument, CWnd, 和CFrameWnd。应该说,对于普通应用,我们并不需要自己实现派生于CCmdTarget的新类,但在系统较为庞大的时候,设计新类型往往能够给系统架构带来更好的特性。以下图为例:

1,在系统资源里添加#define ID_UNDO 130,此ID为CLineCmd中需要实现消息映射的ID;

2,在CSketchCmd为CLienCmd的父类,且继承于CCmdTarget,在其内添加afx_msg void OnCommand();和virtual void OnCmd();

3,OnCommand中实现对OnCmd的调用;

4,在CLineCmd中添加virtual void OnCmd();

5,在CLineCmd中添加消息映射,把ID_UNDO的消息响应函数指向父类中定义的OnCommand();

BEGIN_MESSAGE_MAP(CLineCmd, CCmdTarget)

ON_COMMAND(ID_UNDO,OnCommand)

END_MESSAGE_MAP()

这样,简单的两个派生于CCmdTarget即设计完成。

此时,我们可以试着在主程序框架内动态把ID_UNDO加载入菜单:GetMenu()->AppendMenu(MF_INSERT,ID_UNDO,"undo");很奇怪,系统并没有如我们所愿,响

应OnCommand,并最终实现OnCmd的调用。原因在于MFC对菜单的响应实际是通过调用CCmdTarget::OnCmdMsg()实现,但MFC框架对各个OnCmdMsg的调用过程依次为:框架,视图,文档,可以看到自定义的新类型并没有在此过程内,程序又怎么会知道到哪里去寻找消息映射函数呢?

针对这种情况,为了实现框架内对消息的响应,还必须重载OnCmdMsg,至于选择框架内还是视图内重载则关系不大;我们选择在视图内进行重载,这样在视图内对消息入口进行了重定义,实现了映射。

BOOL CMy123View::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)

{

CLineCmd LineCmd;

if(LineCmd.OnCmdMsg(nID,nCode,pExtra,pHandlerInfo))

return TRUE;

CView::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);

return FALSE;

}

注意:在CSketchCmd内只进行OnCommand的声明,具体的MESSAGE_MAP则在具体子类CLineCmd内进行;本例中,由于虚函数的多态性,最终调用了CLineCmd的OnCmd函数

向CCmdTarget的派生类添加一个接口的实现

向一个类中添加某个接口的实现,这是非常常见的需求,特别是用在事件通知、连接点中更是多见。MFC

类库内的非常多类也都有这样的需求,比如类COleControl就实现了非常多的接口。MFC自己实现的方法都用

的是嵌套类,并且定义了几个宏来简化该过程。用同样的方法,我们也能非常方便的在自己的类中添加一个接

口的实现。CCmdTarget中实现了接口IDispatch,及IUnknown 的三个函数的缺省实现。一般的MFC类都会从CCmdTarget继承,所以这里讲的是典型的向CCmdTarget的派生类添加接口的方法。

比如,有一个类CSampleView从CView中继承。目前要给他添加一个新的接口IMyTest,该接口只有一个空的方法Test()。添加过程如下:

(1)CSampleView类定义中加入以下代码:

DECLARE_INTERFACE_MAP() //声明接口映射

BEGIN_INTERFACE_PART(TestInterface, IMyTest) //声明实现接口IMyTest的嵌套类

STDMETHOD(Test)();

END_INTERFACE_PART(FontNotify2)

(2)CSampleView类实现中加入以下代码:

BEGIN_INTERFACE_MAP(CSampleView, CCmdTarget)

INTERFACE_PART(CSampleView, IID_IMyTest, TestInterface)

END_INTERFACE_MAP()

STDMETHODIMP_(ULONG) CSampleView::XTestInterface::AddRef( )

{

METHOD_PROLOGUE_EX(CSampleView, TestInterface)

return (ULONG)pThis->ExternalAddRef();

}

STDMETHODIMP_(ULONG) CSampleView::XTestInterface::Release( )

{

METHOD_PROLOGUE_EX(CSampleView, TestInterface)

return (ULONG)pThis->ExternalRelease();

}

STDMETHODIMP CSampleView::XTestInterface::QueryInterface( REFIID iid, LPVOID FAR* ppvObj )

{

METHOD_PROLOGUE_EX(CSampleView, TestInterface)

return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj) ;

}

STDMETHODIMP CSampleView::XTestInterface::Test()

{

METHOD_PROLOGUE_EX(CSampleView, TestInterface)

// do something you like

return S_OK ;

}

揭开宏的神秘面纱,看看他到底是什么东西。以下都是简化的版本。

(1)DECLARE_INTERFACE_MAP

struct AFX_INTERFACEMAP_ENTRY

{

const void* piid;

// the interface id (IID) (NULL for aggregate)

size_t nOffset;

// offset of the interface vtable from m_unknown

};

struct AFX_INTERFACEMAP

{

const AFX_INTERFACEMAP* (PASCAL* pfnGetBaseMap)(); // NULL is root class

const AFX_INTERFACEMAP_ENTRY* pEntry; // map for this class

};

#define DECLARE_INTERFACE_MAP() \

private: \

static const AFX_INTERFACEMAP_ENTRY _interfaceEntries[]; \

protected: \

static AFX_DATA const AFX_INTERFACEMAP interfaceMap; \

static const AFX_INTERFACEMAP* PASCAL _GetBaseInterfaceMap(); \

virtual const AFX_INTERFACEMAP* GetInterfaceMap() const; \

(2)BEGIN_INTERFACE_PART/END_INTERFACE_PART

#define BEGIN_INTERFACE_PART(localClass, baseClass) \// 定义了一个嵌套类

class X##localClass : public baseClass \

{ \

public: \

STDMETHOD_(ULONG, AddRef)(); \

STDMETHOD_(ULONG, Release)(); \

STDMETHOD(QueryInterface)(REFIID iid, LPVOID* ppvObj); \

#define END_INTERFACE_PART(localClass) \

} m_x##localClass; \

friend class X##localClass; \

(3)BEGIN_INTERFACE_MAP/INTERFACE_PART/END_INTERFACE_MAP

#define offsetof(s,m) (size_t)&(((s *)0)->m)

#define BEGIN_INTERFACE_MAP(theClass, theBase) \

const AFX_INTERFACEMAP* PASCAL theClass::_GetBaseInterfaceMap() \

{ return &theBase::interfaceMap; } \

const AFX_INTERFACEMAP* theClass::GetInterfaceMap() const \

{ return &theClass::interfaceMap; } \

AFX_COMDAT const AFX_DATADEF AFX_INTERFACEMAP theClass::interfaceMap = \{ &theClass::_GetBaseInterfaceMap, &theClass::_interfaceEntries[0], }; \

AFX_COMDAT const AFX_DATADEF AFX_INTERFACEMAP_ENTRY theClass::_interfaceEntries[] = \

{ \

#define INTERFACE_PART(theClass, iid, localClass) \

{ &iid, offsetof(theClass, m_x##localClass) }, \

#define END_INTERFACE_MAP() \

{ NULL, (size_t)-1 } \

}; \ (4)METHOD_PROLOGUE_EX

#define METHOD_PROLOGUE_EX(theClass, localClass) \

METHOD_PROLOGUE(theClass, localClass) \

#define METHOD_PROLOGUE(theClass, localClass) \

theClass* pThis = \

((theClass*)((BYTE*)this - offsetof(theClass, m_x##localClass))); \

AFX_MANAGE_STATE(pThis->m_pModuleState) \

pThis; // avoid warning from compiler \

METHOD_PROLOGUE 最大的作用就是得到pThis 指针。该宏用在嵌套类的成员函数中,pThis 是其父

类的指针,这里也即是CSampleView 的this 指针。

这些宏和MFC 中的消息映射宏非常的相似,在侯捷的《深入浅出MFC 》中对消息映射宏有非常周详的

讲述。我也无意画蛇添足。他的基本思想就是把各个嵌套类的对象(即m_x 开头的变量)放到一个数组里,这

样在QueryInterface 时就能得到这些接口的指针了,所谓的接口指针 CCmdTarget 包含了三个函数:ExternalAddRef 、ExternalRelease 、ExternalQueryInterface 。这样我

们就不用自己实现IUnknown 接口了,只要简单地调用父类的也就是这些嵌套类对象的地址。

函数就能了,这实在是非常方便。

ExternalQueryInterface 的执行过程就是先在子类中找要查询的接口,如果找到了就返回其接口指针

。如果

未找到就通过GetBaseInterfaceMap 到父类中去找,以此类推。跟消息映射的处理方法是相同的

深度解析VC 中的消息传递机制 什么是消息?

消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉。一个消息,是系统定义

的一个32位的值,他唯一的定义了一个事件,向Windows 发出一个通知,告诉应用程序某个事情发生了。

例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows 发送一个消息给应用程序。

消息本身是作为一个记录传递给应用程序的,这个记录中包含了消息的类型以及其他信息。例如,对

于单击鼠标所产生的消息来说,这个记录中包含了单击鼠标时的坐标。这个记录类型叫做MSG ,MSG 含有

来自windows 应用程序消息队列的消息信息,它在Windows 中声明如下:

typedef struct tagMsg

{

HWND hwnd; 接受该消息的窗口句柄

UINT message; 消息常量标识符,也就是我们通常所说的消息号

WPARAM wParam; 32位消息的特定附加信息,确切含义依赖于消息值

LPARAM lParam; 32位消息的特定附加信息,确切含义依赖于消息值

DWORD time; 消息创建时的时间

POINT pt; 消息创建时的鼠标/光标在屏幕坐标系中的位置

}MSG;

消息可以由系统或者应用程序产生。系统在发生输入事件时产生消息。举个例子, 当用户敲键, 移动鼠标或者单击控件。系统也产生消息以响应由应用程序带来的变化, 比如应用程序改变系统字体改变窗体大小。应用程序可以产生消息使窗体执行任务,或者与其他应用程序中的窗口通讯。

消息中有什么?

我们给出了上面的注释,是不是会对消息结构有了一个比较清楚的认识?如果还没有,那么我们再试着给出下面的解释:

hwnd 32位的窗口句柄。窗口可以是任何类型的屏幕对象,因为Win32能够维护大多数可视对象的句柄(窗口、对话框、按钮、编辑框等)。

message用于区别其他消息的常量值,这些常量可以是Windows单元中预定义的常量,也可以是自定义的常量。消息标识符以常量命名的方式指出消息的含义。当窗口过程接收到消息之后,他就会使用消息标识符来决定如何处理消息。例如、WM_PAINT告诉窗口过程窗体客户区被改变了需要重绘。符号常量指定系统消息属于的类别,其前缀指明了处理解释消息的窗体的类型。

wParam 通常是一个与消息有关的常量值,也可能是窗口或控件的句柄。

lParam 通常是一个指向内存中数据的指针。由于WParam、lParam和Pointer都是32位的,因此,它们之间可以相互转换。

消息标识符的值

系统保留消息标识符的值在0x0000在0x03ff(WM_USER-1)范围。这些值被系统定义消息使用。应用程序不能使用这些值给自己的消息。应用程序消息从WM_USER(0X0400)到0X7FFF,或0XC000到0XFFFF;WM_USER到0X7FFF范围的消息由应用程序自己使用;0XC000到0XFFFF范围的消息用来和其他应用程序通信,我们顺便说一下具有标志性的消息值:

WM_NULL---0x0000 空消息。

0x0001----0x0087 主要是窗口消息。

0x00A0----0x00A9 非客户区消息

0x0100----0x0108 键盘消息

0x0111----0x0126 菜单消息

0x0132----0x0138 颜色控制消息

0x0200----0x020A 鼠标消息

0x0211----0x0213 菜单循环消息

0x0220----0x0230 多文档消息

0x03E0----0x03E8 DDE消息

0x0400 WM_USER

0x8000 WM_APP

0x0400----0x7FFF 应用程序自定义私有消息

消息有的分类?

其实,windows中的消息虽然很多,但是种类并不繁杂,大体上有3种:窗口消息、命令消息和控件通知消息。

窗口消息大概是系统中最为常见的消息,它是指由操作系统和控制其他窗口的窗口所使用的消息。例如CreateWindow、DestroyWindow和MoveWindow等都会激发窗口消息,还有我们在上面谈到的单击鼠标所产生的消息也是一种窗口消息。

命令消息,这是一种特殊的窗口消息,他用来处理从一个窗口发送到另一个窗口的用户请求,例如按下一个按钮,他就会向主窗口发送一个命令消息。

控件通知消息,是指这样一种消息,一个窗口内的子控件发生了一些事情,需要通知父窗口。通知消息只适用于标准的窗口控件如按钮、列表框、组合框、编辑框,以及Windows公共控件如树状视图、列表视图等。例如,单击或双击一个控件、在控件中选择部分文本、操作控件的滚动条都会产生通知消息。她类似于命令消息,当用户与控件窗口交互时,那么控件通知消息就会从控件窗口发送到它的主窗口。但是这种消息的存在并不是为了处理用户命令,而是为了让主窗口能够改变控件,例如加载、显示数据。例如按下一个按钮,他向父窗口发送的消息也可以看作是一个控件通知消息;单击鼠标所产生的消息可以由主窗口直接处理,然后交给控件窗口处理。

其中窗口消息及控件通知消息主要由窗口类即直接或间接由CWND类派生类处理。相对窗口消息及控件通知消息而言,命令消息的处理对象范围就广得多,它不仅可以由窗口类处理,还可以由文档类,文档模板类及应用类所处理。

队列消息和非队列消息

从消息的发送途径来看,消息可以分成2种:队列消息和非队列消息。消息队列由可以分成系统消息队列和线程消息队列。系统消息队列由Windows维护,线程消息队列则由每个GUI线程自己进行维护,为避免给non-GUI现成创建消息队列,所有线程产生时并没有消息队列,仅当线程第一次调用GDI函数数系统给线程创建一个消息队列。队列消息送到系统消息队列,然后到线程消息队列;非队列消息直接送给目的窗口过程。

对于队列消息,最常见的是鼠标和键盘触发的消息,例如WM_MOUSERMOVE,WM_CHAR等消息,还有一些其它的消息,例如:WM_PAINT、WM_TIMER和WM_QUIT。当鼠标、键盘事件被触发后,相应的鼠标或键盘驱动程序就会把这些事件转换成相应的消息,然后输送到系统消息队列,由Windows系统去进行处理。Windows系统则在适当的时机,从系统消息队列中取出一个消息,根据前面我们所说的MSG消息结构确定消息是要被送往那个窗口,然后把取出的消息送往创建窗口的线程的相应队列,下面的事情就该由线程消息队列操心了,Windows开始忙自己的事情去了。线程看到自己的消息队列中有消息,就从队列中取出来,通过操作系统发送到合适的窗口过程去处理。

一般来讲,系统总是将消息Post在消息队列的末尾。这样保证窗口以先进先出的顺序接受消息。然而,WM_PAINT是一个例外,同一个窗口的多个 WM_PAINT被合并成一个 WM_PAINT 消息, 合并所有的无效区域到一个无效区域。合并WM_PAIN的目的是为了减少刷新窗口的次数。

非队列消息将会绕过系统队列和消息队列,直接将消息发送到窗口过程,。系统发送非队列消息通知窗口,系统发送消息通知窗口。例如,当用户激活一个窗口系统发送WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR。这些消息通知窗口它被激活了。非队列消息也可以由当应用程序调用系统函数产生。例如,当程序调用SetWindowPos系统发送WM_WINDOWPOSCHANGED消息。一些函数也发送非队列消息,例如下面我们要谈到的函数。

消息的发送

了解了上面的这些基础理论之后,我们就可以进行一下简单的消息发送与接收。

把一个消息发送到窗口有3种方式:发送、寄送和广播。

发送消息的函数有SendMessage、SendMessageCallback、SendNotifyMessage、SendMessageTimeout;寄送消息的函数主要有PostMessage、PostThreadMessage、PostQuitMessage;广播消息的函数我知道的只有BroadcastSystemMessage、BroadcastSystemMessageEx。

SendMessage的原型如下:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam),这个函数主要是向一个或多个窗口发送一条消息,一直等到消息被处理之后才会返回。不过需要注意的是,如果接收消息的窗口是同一个应用程序的一部分,那么这个窗口的窗口函数就被作为一个子程序马上被调用;如果接收消息的窗口是被另外的线程所创建的,那么窗口系统就切换到相应的线程并且调用相应的窗口函数,这条消息不会被放进目标应用程序队列中。函数的返回值是由接收消息的窗口的窗口函数返回,返回的值取决于被发送的消息。

PostMessage的原型如下:BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam),该函数把一条消息放置到创建hWnd窗口的线程的消息队列中,该函数不等消息被处理就马上将控制返回。需要注意的是,如果hWnd参数为HWND_BROADCAST,那么,消息将被寄送给系统中的所有的重叠窗口和弹出窗口,但是子窗口不会收到该消息;如果hWnd参数为NULL,则该函数类似于将dwThreadID参数设置成当前线程的标志来调用PostThreadMEssage函数。

从上面的这2个具有代表性的函数,我们可以看出消息的发送方式和寄送方式的区别所在:被发送的消息是否会被立即处理,函数是否立即返回。被发送的消息会被立即处理,处理完毕后函数才会返回;被寄送的消息不会被立即处理,他被放到一个先进先出的队列中,一直等到应用程序空线的时候才会被处理,不过函数放置消息后立即返回。

实际上,发送消息到一个窗口处理过程和直接调用窗口处理过程之间并没有太大的区别,他们直接的唯一区别就在于你可以要求操作系统截获所有被发送的消息,但是不能够截获对窗口处理过程的直接调用。

以寄送方式发送的消息通常是与用户输入事件相对应的,因为这些事件不是十分紧迫,可以进行缓慢的缓冲处理,例如鼠标、键盘消息会被寄送,而按钮等消息则会被发送。

广播消息用得比较少,BroadcastSystemMessage函数原型如下:

long BroadcastSystemMessage(DWORD dwFlags,LPDWORD lpdwRecipients,UINT uiMessage,WPARAM wParam,LPARAM lParam);

该函数可以向指定的接收者发送一条消息,这些接收者可以是应用程序、可安装的驱动程序、网络驱

动程序、系统级别的设备驱动消息和他们的任意组合。需要注意的是,如果dwFlags参数是BSF_QUERY并且

至少一个接收者返回了BROADCAST_QUERY_DENY,则返回值为0,如果没有指定BSF_QUERY,则函数将消息发

送给所有接收者,并且忽略其返回值。

消息的接收

消息的接收主要有3个函数:GetMessage、PeekMessage、WaitMessage。

GetMessage原型如下:BOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax);

该函数用来获取与hWnd参数所指定的窗口相关的且wMsgFilterMin和wMsgFilterMax参数所给出的消息

值范围内的消息。需要注意的是,如果hWnd为NULL,则GetMessage获取属于调用该函数应用程序的任一窗

口的消息,如果wMsgFilterMin和wMsgFilterMax都是0,则GetMessage就返回所有可得到的消息。函数获

取之后将删除消息队列中的除WM_PAINT消息之外的其他消息,至于WM_PAINT则只有在其处理之后才被删除。

PeekMessage原型如下:BOOL PeekMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg);

该函数用于查看应用程序的消息队列,如果其中有消息就将其放入lpMsg所指的结构中,不过,与GetMessage不同的是,PeekMessage函数不会等到有消息放入队列时才返回。同样,如果hWnd为NULL,则PeekMessage获取属于调用该函数应用程序的任一窗口的消息,如果hWnd=-1,那么函数只返回把hWnd参数

为NULL的PostAppMessage函数送去的消息。如果wMsgFilterMin和wMsgFilterMax都是0,则PeekMessage

就返回所有可得到的消息。函数获取之后将删除消息队列中的除WM_PAINT消息之外的其他消息,至于WM_PAINT则只有在其处理之后才被删除。

WaitMessage原型如下:BOOL VaitMessage();当一个应用程序无事可做时,该函数就将控制权交给另

外的应用程序,同时将该应用程序挂起,直到一个新的消息被放入应用程序的队列之中才返回。

消息的处理

接下来我们谈一下消息的处理,首先我们来看一下VC中的消息泵: while(GetMessage(&msg, NULL, 0, 0))

{

if(!TranslateAccelerator(msg.hWnd, hAccelTable, &msg))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

首先,GetMessage从进程的主线程的消息队列中获取一个消息并将它复制到MSG结构,如果队列中没有消息,则GetMessage函数将等待一个消息的到来以后才返回。如果你将一个窗口句柄作为第二个参数传入GetMessage,那么只有指定窗口的的消息可以从队列中获得。GetMessage也可以从消息队列中过滤消息只接受消息队列中落在范围内的消息。这时候就要利用GetMessage/PeekMessage指定一个消息过滤器。这个过滤器是一个消息标识符的范围或者是一个窗体句柄,或者两者同时指定。当应用程序要查找一个后入消息队列的消息是很有用。WM_KEYFIRST 和 WM_KEYLAST 常量用于接受所有的键盘消息。 WM_MOUSEFIRST 和WM_MOUSELAST 常量用于接受所有的鼠标消息。

然后TranslateAccelerator判断该消息是不是一个按键消息并且是一个加速键消息,如果是,则该函数将把几个按键消息转换成一个加速键消息传递给窗口的回调函数。处理了加速键之后,函数TranslateMessage将把两个按键消息WM_KEYDOWN和WM_KEYUP转换成一个WM_CHAR,不过需要注意的是,消息WM_KEYDOWN,WM_KEYUP仍然将传递给窗口的回调函数。

处理完之后,DispatchMessage函数将把此消息发送给该消息指定的窗口中已设定的回调函数。如果消息是WM_QUIT,则GetMessage返回0,从而退出循环体。应用程序可以使用PostQuitMessage来结束自己的消息循环。通常在主窗口的WM_DESTROY消息中调用。

下面我们举一个常见的小例子来说明这个消息泵的运用:

if (::PeekMessage(&msg, m_hWnd, WM_KEYFIRST,WM_KEYLAST, PM_REMOVE))

{

if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)...

}

这里我们接受所有的键盘消息,所以就用WM_KEYFIRST 和 WM_KEYLAST作为参数。最后一个参数可以是PM_NOREMOVE 或者 PM_REMOVE,表示消息信息是否应该从消息队列中删除。

所以这段小代码就是判断是否按下了Esc键,如果是就进行处理。

窗口过程是一个用于处理所有发送到这个窗口的消息的函数。任何一个窗口类都有一个窗口过程。同一个类的窗口使用同样的窗口过程来响应消息。系统发送消息给窗口过程将消息数据作为参数传递给他,消息到来之后,按照消息类型排序进行处理,其中的参数则用来区分不同的消息,窗口过程使用参数产生合适行为。

一个窗口过程不经常忽略消息,如果他不处理,它会将消息传回到执行默认的处理。窗口过程通过调用DefWindowProc来做这个处理。窗口过程必须return一个值作为它的消息处理结果。大多数窗口只处理小部分消息和将其他的通过DefWindowProc传递给系统做默认的处理。窗口过程被所有属于同一个类的窗口共享,能为不同的窗口处理消息。下面我们来看一下具体的实例:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

int wmId, wmEvent;

PAINTSTRUCT ps;

HDC hdc;

TCHAR szHello[MAX_LOADSTRING];

LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

switch (message)

{

case WM_COMMAND:

wmId = LOWORD(wParam);

wmEvent = HIWORD(wParam);

// Parse the menu selections:

switch (wmId)

{

case IDM_ABOUT:

DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);

break;

case IDM_EXIT:

DestroyWindow(hWnd);

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

break;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

// TODO: Add any drawing code here...

RECT rt;

GetClientRect(hWnd, &rt);

DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);

EndPaint(hWnd, &ps);

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

return 0;

}

消息分流器

通常的窗口过程是通过一个switch语句来实现的,这个事情很烦,有没有更简便的方法呢?有,那就是消息分流器,利用消息分流器,我们可以把switch语句分成更小的函数,每一个消息都对应一个小函数,这样做的好处就是对消息更容易管理。

之所以被称为消息分流器,就是因为它可以对任何消息进行分流。下面我们做一个函数就很清楚了:

void MsgCracker(HWND hWnd,int id,HWND hWndCtl,UINT codeNotify)

{

switch(id)

{

case ID_A:

if(codeNotify==EN_CHANGE)...

break;

case ID_B:

if(codeNotify==BN_CLICKED)...

break;

....

}

}

然后我们修改一下窗口过程:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

switch(message)

{

HANDLE_MSG(hWnd,WM_COMMAND,MsgCracker);

HANDLE_MSG(hWnd,WM_DESTROY,MsgCracker);

default:

return DefWindowProc(hWnd, message, wParam, lParam);

}

return 0;

}

在WindowsX.h中定义了如下的HANDLE_MSG宏:

#define HANDLE_MSG(hwnd,msg,fn) \

switch(msg): return HANDLE_##msg((hwnd),(wParam),(lParam),(fn));

实际上,HANDLE_WM_XXXX都是宏,例如:HANDLE_MSG(hWnd,WM_COMMAND,MsgCracker);将被转换成如下

定义:

#define HANDLE_WM_COMMAND(hwnd,wParam,lParam,fn)\

((fn)((hwnd),(int)(LOWORD(wParam)),(HWND)(lParam),(UINT)HIWORD(wParam)),0L);

好了,事情到了这一步,应该一切都明朗了。

不过,我们发现在windowsx.h里面还有一个宏:FORWARD_WM_XXXX,我们还是那WM_COMMAND为例,进行

分析:

#define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \

(void)(fn)((hwnd), WM_COMMAND, MAKEWPARAM((UINT)(id),(UINT)(codeNotify)), (LPARAM)(HWND)(hwndCtl))

所以实际上,FORWARD_WM_XXXX将消息参数进行了重新构造,生成了wParam && lParam,然后调用了我

们定义的函数。

MFC消息的处理实现方式

初看MFC中的各种消息,以及在头脑中根深蒂固的C++的影响,我们可能很自然的就会想到利用C++的三

大特性之一:虚拟机制来实现消息的传递,但是经过分析,我们看到事情并不是想我们想象的那样,在MFC

中消息是通过一种所谓的消息映射机制来处理的。

为什么呢?在潘爱民老师翻译的《Visual C++技术内幕》(第4版)中给出了详细的原因说明,我再

简要的说一遍。在CWnd类中大约有110个消息,还有其它的MFC的类呢,算起来消息太多了,在C++中对程

序中用到的每一个派生类都要有一个vtable,每一个虚函数在vtable中都要占用一个4字节大小的入口地

址,这样一来,对于每个特定类型的窗口或控件,应用程序都需要一个440KB大小的表来支持虚拟消息控

件函数。

如果说上面的窗口或控件可以勉强实现的话,那么对于菜单命令消息及按钮命令消息呢?因为不同的

应用程序有不同的菜单和按钮,我们怎么处理呢?在MFC库的这种消息映射系统就避免了使用大的vtable,

并且能够在处理常规Windows消息的同时处理各种各样的应用程序的命令消息。

说白了,MFC中的消息机制其实质是一张巨大的消息及其处理函数的一一对应表,然后加上分析处理这

张表的应用框架内部的一些程序代码.这样就可以避免在SDK编程中用到的繁琐的CASE语句。

MFC的消息映射的基类CCmdTarget

如果你想让你的控件能够进行消息映射,就必须从CCmdTarget类中派生。CCmdTarget类是MFC处理命令消息的基础、核心。MFC为该类设计了许多成员函数和一些成员数据,基本上是为了解决消息映射问题的,所有响应消息或事件的类都从它派生,例如:应用程序类、框架类、文档类、视图类和各种各样的控件类等等,还有很多。

不过这个类里面有2个函数对消息映射非常重要,一个是静态成员函数DispatchCmdMsg,另一个是虚函数OnCmdMsg。

DispatchCmdMsg专门供MFC内部使用,用来分发Windows消息。OnCmdMsg用来传递和发送消息、更新用户界面对象的状态。

CCmdTarget对OnCmdMsg的默认实现:在当前命令目标(this所指)的类和基类的消息映射数组里搜索指定命令消息的消息处理函数。

这里使用虚拟函数GetMessageMap得到命令目标类的消息映射入口数组_messageEntries,然后在数组里匹配命令消息ID相同、控制通知代码也相同的消息映射条目。其中GetMessageMap是虚拟函数,所以可以确认当前命令目标的确切类。

如果找到了一个匹配的消息映射条目,则使用DispachCmdMsg调用这个处理函数;

如果没有找到,则使用_GetBaseMessageMap得到基类的消息映射数组,查找,直到找到或搜寻了所有的基类(到CCmdTarget)为止;

如果最后没有找到,则返回FASLE。

每个从CCmdTarget派生的命令目标类都可以覆盖OnCmdMsg,利用它来确定是否可以处理某条命令,如果不能,就通过调用下一命令目标的OnCmdMsg,把该命令送给下一个命令目标处理。通常,派生类覆盖OnCmdMsg时,要调用基类的被覆盖的OnCmdMsg。

在MFC框架中,一些MFC命令目标类覆盖了OnCmdMsg,如框架窗口类覆盖了该函数,实现了MFC的标准命令消息发送路径。必要的话,应用程序也可以覆盖OnCmdMsg,改变一个或多个类中的发送规定,实现与标准框架发送规定不同的发送路径。例如,在以下情况可以作这样的处理:在要打断发送顺序的类中把命令传给一个非MFC默认对象;在新的非默认对象中或在可能要传出命令的命令目标中。

消息映射的内容

通过ClassWizard为我们生成的代码,我们可以看到,消息映射基本上分为2大部分:

在头文件(.h)中有一个宏DECLARE_MESSAGE_MAP(),他被放在了类的末尾,是一个public属性的;与之对应的是在实现部分(.cpp)增加了一章消息映射表,内容如下:

BEGIN_MESSAGE_MAP(当前类, 当前类的基类)

file://{{AFX_MSG_MAP(CMainFrame)

消息的入口项

file://}}AFX_MSG_MAP

END_MESSAGE_MAP()

但是仅是这两项还远不足以完成一条消息,要是一个消息工作,必须有以下3个部分去协作:

1.在类的定义中加入相应的函数声明;

2.在类的消息映射表中加入相应的消息映射入口项;

3.在类的实现中加入相应的函数体;

消息的添加

有了上面的这些只是作为基础,我们接下来就做我们最熟悉、最常用的工作:添加消息。MFC消息的添加主要有2种方法:自动/手动,我们就以这2种方法为例,说一下如何添加消息。

1、利用Class Wizard实现自动添加

在菜单中选择View-->Class Wizard,也可以用单击鼠标右键,选择Class Wizard,同样可以激活Class Wizard。选择Message Map标签,从Class name组合框中选取我们想要添加消息的类。在Object IDs列表框中,选取类的名称。此时, Messages列表框显示该类的大多数(若不是全部的话)可重载成员函数和窗口消息。类重载显示在列表的上部,以实际虚构成员函数的大小写字母来表示。其他为窗口消息,以大写字母出现,描述了实际窗口所能响应的消息ID。选中我们向添加的消息,单击Add Function按钮,Class Wizard 自动将该消息添加进来。

有时候,我们想要添加的消息本应该出现在Message列表中,可是就是找不到,怎么办?不要着急,我们可以利用Class Wizard上Class Info标签以扩展消息列表。在该页中,找到Message Filter组合框,通过它可以改变首页中Messages列表框中的选项。这里,我们选择Window,从而显示所有的窗口消息,一把情况下,你想要添加的消息就可以在Message列表框中出现了,如果还没有,那就接着往下看:)

2、手动地添加消息处理函数

如果在Messages列表框中仍然看不到我们想要的消息,那么该消息可能是被系统忽略掉或者是你自己创建的,在这种情况下,就必须自己手工添加。根据我们前面所说的消息工作的3个部件,我们一一进行处理:

1) 在类的. h文件中添加处理函数的声明,紧接在//}}AFX_MSG行之后加入声明,注意:一定要以afx_msg开头。

通常,添加处理函数声明的最好的地方是源代码中Class Wizard维护的表下面,但是在它标记其领域的{{}}括弧外面。这些括弧中的任何东西都将会被Class Wizard销毁。

2) 接着,在用户类的.cpp文件中找到//}}AFX_MSG_MAP行,紧接在它之后加入消息入口项。同样,也是放在{ {} }的外面

3) 最后,在该文件中添加消息处理函数的实体

mfc资料

你创建的是一个对话框程序,所以只有CMyApp 和CMyDlg 两个类。 但如果创建的是个单文档或者多文档程序。那么就有5个类。 程序是按顺序执行的,虽然都被封装成了类对象,看起来模块话,其实还是按顺序执行的,APP这个对象那个先于dlg构建。所以很多需要初始化的东西直接在App的成员initInstance 中编写。dlg中编写的基本都是一些与对话框相关的逻辑。 CMyApp是主线程类。他的InitInstance函数中会用CMyDlg构造一个对象,产生主对话框,CMyDlg是对话框类的一个派生类。两个类功能不同。 MFC的东西很复杂,不是三言两语可以说清楚的,可以参考下深入浅出mfc等书。CMyApp负责程序主框架的工作,可以理解为WinMain的封装。 CMyDlg是主对话框了,负责界面显示,消息循环等。 ------解决方案-------------------- CMyApp派生于CWinApp类,CMyDlg派生于CDialog类 程序运行时先执行CMyApp的InitInstance()函数 在InitInstance()中会有这样的代码 CMyDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); 一个最基本的单文档视图的MFC程序,包含CxxApp、CxxDoc、CMainFrame、CxxView和CAboutDlg五个类。 它们在程序开始运行时被创建的顺序是:CxxApp 、CxxDoc 、CMainFrame 、CxxView 、CAboutDlg 。

C**App()定义了窗体加载之前需要做的预处理。比如一个加密的软件,打 开后提示用户输入密码。这个事件的处理程序就要写在C**App()的 InitInstance(中。 CMainFrame()包含了对工具栏、状态栏、窗口的定义。 C**View包含了最主要的处理功能,如菜单操作、快捷键、用户交互操作等。 CAboutDlg定义了ABOUT对话框。 其中,前四个都是在程序主窗口出现之前被创建的,CAboutDlg是在“关于”对话框弹出 时被创建的 1CAboutDlg //这个是关于对话框里面是构造和析构2CMainFrame //主框架`是在窗口生成之前准备工作全在这吗 ?3CTestApp//这个是什么`initlnstance()在这里也是初始化什 么对象 ? 4CTestDoc//这是文档`是管理哪些文档`对初学者来说很少用 呐 ?5CTestView视图`这个常用 OnDraw我了解一些`我想知道`是不是默认就调 用一次 ? 还有个问题啊`我想加个音乐`虽然加成功了`但是`我一直不明白加在哪个函数里 `运行就有音乐?看过孙鑫的教程后来忘了`各位高手各抒已见,互相学习 LZ需要系统地学习一下。 CTestApp是基于WinApp的,WinApp封装了程序的主入口WinMain,WinMain就和c语言的main函数地位一样,是Win32程序的入口。在MFC的封装中,一个程序启动,Windows调用WinMain,这个WinMain函数现在由MFC事先写好藏好了,你不能也不需要修改,在这个预定义的WinMain里面会调用CWinApp的InitInstrance函数。你仔细看你CTestApp::InitInstrance函数,在这里一个CMainFrame的对象被创建,文档模板被创建,主窗口通过ShowWindow(SW_SHOW)被显示出来。 CMainFrame是个框架,是你整个应用程序的主窗口,他负责管理应用程序的菜单,工具栏,状态栏等。中间的区域,成为客户区,由View类来管理,View类也是一个窗口,他是MainFrame的子窗口。OnDraw函数负责绘制客户区的内容,该函数会被多次调用,他可以被你自己调用,比如你调用View类的UpdateWindow,或者在Document类中调用UpdateAllViews等等,MFC自动会调用OnDraw。他还会被Windows调用,Windows在需要刷新窗口的时候发送给窗口WM_PAINT消息,MFC事先已经预定义了,在响应WM_PAINT消息的时候会调用OnDraw。何时Windows会发送WM_PAINT呢,比如窗口从最小化还原,比如窗口被用户改变了 大小等等。这部分内容最好看看Windows GDI,Windows GDI是Windows操作系统整个可视化界面的基础。

MFC知识点(自己整理的,只供参考)

知识点:不是很全面,只供参考 第一章 Windows应用程序使用的界面是由各种图形元素组成的图形界面(GUI)。 Windows提供了大量预定义的用C语言编写的函数,这些函数就叫做API(Application Programming Interface)函数。 在Windows应用程序中,存在着许多与DOS应用程序不同的复杂对象,例如窗口、按钮、滚动条等等。Windows把为这种复杂对象所定义的标识叫做句柄。 常用的句柄类型:HWND 窗口句柄,HDC 图形设备环境句柄,HINSTANCE 当前程序应用实例句柄,HBITMAP 位图句柄,HICON 图标句柄,HCURSOR 光标句柄,HBRUSH 画刷句柄,HPEN 画笔句柄,HFONT 字体句柄,HMENU 菜单句柄,HFILE 文件句柄 事件的描述是一个消息 消息的结构: typedef struct tagMSG { HWND hwnd; //产生消息的窗口句柄 UINT message;//消息的标识码 WPARAM wParam;//消息的附加信息1 LPARAM lParam;//消息的附加信息2 DWORD time; //消息进入消息队列的时刻 POINT pt; //表示发送该消息时鼠标的位置 }MSG; 消息循环: while(GetMessage(&msg,NULL,NULL,NULL))//系统处理了消息后返回 { TranslateMessage(&msg);//把键盘消息翻译成字符消息 DispatchMessage(&msg);//把消息派发给Windows系统 创建窗口的三个步骤: 注册窗口类: RegisterClass(&wc); 创建窗口: hwnd=CreateWindow( lpszClassName, "Windows", WS_OVERLAPPEDWINDOW, 120,50,800,600, NULL, NULL, hInstance, NULL); 显示窗口: ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); 大题:用函数封装Windows程序(P16) 第二章

MFC对话框程序中的各组件常用方法

MFC对话框程序中的各组件常用方法: Static Text: 将ID号改成唯一的一个,如:IDC_XX,然后进一次类向导点确定产生这个ID,之后更改Caption属性: GetDlgItem(IDC_XX)->SetWindowText(L"dsgdhfgdffd"); 设置字体: CFont *pFont = new CFont; pFont->CreatePointFont(120,_T("华文行楷")); GetDlgItem(IDC_XX)->SetFont(pFont); Edit Control: 设置文本: SetDlgItemText(IDC_XX,L"iuewurebfdjf"); 获取所有输入: 建立类向导创建一个成员变量(假设是shuru1,shuru2……)类型选value,变量类型任选。 UpdateData(true); GetDlgItem(IDC_XX)->SetWindowText(shuru1); 第一句更新所有建立了变量的对话框组件,获取输入的值。第二句将前面的IDC_XX的静态文本内容改为shuru1输入的内容。 若类型选用control: 1.设置只读属性: shuru1.SetReadOnly(true); 2.判断edit中光标状态并得到选中内容(richedit同样适用) int nStart, nEnd; CString strTemp; shuru1.GetSel(nStart, nEnd); if(nStart == nEnd) { strTemp.Format(_T(" 光标在%d" ), nStart); AfxMessageBox(strTemp); } else { //得到edit选中的内容 shuru1.GetWindowText(strTemp); strTemp = strTemp.Mid(nStart,nEnd-nStart); AfxMessageBox(strTemp); } 其中nStart和nEnd分别表示光标的起始和终止位置,从0开始。strTemp.Format 方法用于格式化字符串。AfxMessageBox(strTemp)显示一个提示对话框,其内容是字符串strTemp。 strTemp = strTemp.Mid(nStart,nEnd-nStart)返回一个被截取的字符串,从nStart开始,长度为nEnd-nStart。如果nStart == nEnd说明没有选择文本。 注:SetSel(0,-1)表示全选;SetSel(-1,i)表示删除所选。

常用的MFC类及其作用

常用的MFC类及其作用 分类:MFC基础类专区2008-10-14 11:16 445人阅读评论(1) 收藏举报 1.CRuntimeClass结构 继承自CObject的类都有一个与它相关的CRuntimeClass结构,用来在运行时获得对象以及其基类的信息。 要使用CRuntimeClass结构,必需借助于RUNTIME_CLASS()宏和其他有关运行时类型识别的宏。 2.CObject CObject类的作用: a.对象诊断:MFC提供了两种对象的诊断机制,一种是利用成员含数AssertValid 进行对象有效性检查,这样可以使类在继续运行以前对自已进行正确性检查。另一种是利用成员含数Dump输出对象的数据成员的值,诊断信息以文本形式放入一个数据流中,用于调试器的输出窗口信息显示。这两种诊断只能用于Debug版的应用程序。 b.CObject类提供了GetRuntimeClass与IsKindOf两个成员含数来支持运行时类型识别。GetRunntimeClass根据对象的类返回一个CRuntimeClass结构的指针,它包含了一个类的运行信息,含数IsKindOf用于测试对象与给定类的关系。 c.提供对象的序列化。必须在类的定义中包含DECLARE_SERIAL宏,并且在类的实现文件中加入包含IMPLEMENT_SERIAL宏. https://www.wendangku.net/doc/b35211799.html,mdTarget 该类直接从CObject类派生而来. 它负责将消息发送到能够响应这些消息的对象。它是所有能实行消息映射MFC类的基类,如CWinThread,CWinApp,CWnd,CView,CDocument等类。CCmdTarget 类的主要功能包括消息发送,设置光标和支持自动化. a.消息发送:MFC应用程序为每个CCmdTarget派生类创建一个称为<消息映射表>的<静态数据结构>,该消息映射结构将消息映射到对象所对应的消息处理含数

常用MFC和API函数

常用MFC和API函数 索引 CArchive类:用于二进制保存档案 CBitmap类:封装Windows的图形设备接口(GDI)位图 CBrush类:封装图形设备接口(GDI)中的画刷 CButton类:提供Windows按钮控件的功能 CByteArray类:该类支持动态的字节数组 CCmdUI类:该类仅用于ON_UPDATE_COMMAND_UI处理函数中 CColorDialog类:封装标准颜色对话框 CDC类:定义设备环境对象类 CDialog类:所有对话框(模态或非模态)的基类 CDocument类:提供用户定义的文档类的基本功能 CEdit类:是一个用于编辑控件的类 CFile类:该类是基本文件类的基类 CFileDialog类:封装了打开和保存文件的标准对话框 CFindReplaceDialog类:封装了标准查找/替换对话框 CFont类:封装了Windows图形设备接口(GDI)中的字体对象 CFontDialog类:封装了字体选择对话框 CGdiObject类:GDI绘图工具的基类 CIPAddressCtrl类:提供了IP地址控件的功能 CImageList类:管理大小相同的图标或位图集 CMenu类:封装应用程序菜单栏和弹出式菜单 CPen类:封装了Windows图形设备接口(GDI)中的画笔对象 CPoint类:操作CPoint和POINT结构 CRect类:封装了一个矩形区域及相关操作 CRgn类:封装用于操作窗口中的椭圆、多边形或者不规则区域的GDI区域 CSize类:用于表示相对坐标或位置 CSpinButtonCtrl类:旋转控件Spin的控制类 CStatusBar类:状态栏窗口的基类 CString类:处理字符串 CStringList类:支持CString对象的列表 CWinApp类:派生的程序对象的基类 CWnd类:提供所有窗口类的基本函数 API函数 CArchive类:用于二进制保存档案 CArchive::CArchive 建立一个CArchive对象 CArchive(CFile* pFile,UINT nMode,int nBufSize=4096,void* lpBuf=NULL); 参数:pFile 指向CFile对象的指针,这个CFile对象是数据的最终源或目的;nMode是标志,取值为CArchive::load时,从文档中加载数据(要求CFile读许可),取值为CArchive::store时,将数据存入文档(要求CFile写许可);nBufSize 指定内部文件缓冲区的大小(按字节计); lpBuf 指向大小为nBufSize的缓冲区,若未指定,则从局部堆中分配一缓冲区,

C++_MFC快速超简单入门

C++ MFC快速超简单入门学习 注意:红色字体为重要的信息,必须理解并记住。 在学习MFC之前,你必须对C++的“类和对象有一定的认识和理解,因为MFC就是C++完全的面向对象设计,它里面封装了好多类,我们只要调用就OK,就像C语言调用库函数一样,直接使用,这就是C++ 第一特性:封装性,第二性就是继承与派生, 这个在MFC中体现得淋淋至间(字打错了)。如果不懂,我再来解释一下,例:有一个商品类,class GOODS 商品属性有名字,价格 它可作为一个基类,我可以派上出苹果类,class Apple :public GOODS . 苹果属性出了继承了商品的属性名字,价格之外,还可派 生出,颜色,等属性,继承与派生就是一个是另一个的子集,但是这 个子集不仅包括父集的特征,还具有一些新的特性,懂了吧,这样。MFC其中重要的类是:CDialog 对话框类,CEdit,(编辑框 类)CButton,(按钮类)CRadio(单选钮类),这些都是作为基类,由我们自己定义的类去派生它们。 好了,现在先了解一下什么是MFC吧,请看当前目录下的MFC入门知识的幻灯片1—20张,或大概的浏览一下当前目录下的其它连个word文件,后面的幻灯片我觉得没必要看了,因为是快速吗,节约时间,(首先看不懂没关系,)但但看完之后,必须掌握如下知识: 1.MFC是作什么用的?与以前我们写的C,C++语言有什 么不同。以及它的一些优点, 不同,以前的是控制台的界面不好看,不友好,操作不 方便,黑框框的一片。 MFC反之。 优点:可用极少的代码实现强大的功能, 2.关于MFC的一些术语,概念啊

3.你要知道MFC的对话框是由控件组成的,具有 哪些控件(例按钮:Button, 单选钮:radio,Edit)例:要知道MFC的编程的原则,也就是宗旨理念吧,“消息映射,事件驱动“,这句话要记住并理解,很重要,真的。那到底是什么意思呢? 现实举例:一个人具备一种“感知“的能力,(也可称消息吧),当用火接近这个人时(发生的事件),就会(驱动)这个人做出反应,远离”火“, 用MFC举例:一个按钮有什么消息啊,我可以单 击它,所以它具备单击的消息: 第一个就是左键单击的消息,第二个 就是双击的消息,见名思议就 OK了。我单击这个按钮要产生某个事件, 我就可以第一步,先给按钮添加一个消息响应函 数,意思就是当我单击按钮时,就调用那个函数, 按钮时时刻刻都处于待命的状态, 假如添加的函数如下: void CDsDlg::OnButton1() { AfxMessageB ox(“我单击了这个按钮”);

MFC常用函数

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★//这一页的代码最重要了,呵呵……什么都在这里面呢; 单文档新建:CWinApp_________docManager->docSingleTemplate的OpenDocumentFile函数参数为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。 多文档新建:CWinApp_________docManager->docMultTemplate的OpenDocumentFile函数参数为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。 单文档打开:CWinApp_________docManager中经过一个打开对话框传递参数,中途还调用了APP的OpenDocumentFile,当然如果我们的APP重载了这个函数也要调用我们的但是我们的函数一定别忘记最后返回是调用父类的此函数___________docSingleTemplate的OpenDocumentFile函数参数不为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。 多文档打开:CWinApp_________docManager中经过一个打开对话框传递参数,中途还调用了APP的OpenDocumentFile,当然如果我们的APP重载了这个函数也要调用我们的但是我们的函数一定别忘记最后返回是调用父类的此函数___________docMultTemplate的OpenDocumentFile函数参数不为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。 他们两个只有在docMultTemplate和docSingleTemplate的OpenDocumentFile函数中的动作不同,单文档负责新建框架类和视类但是如果存在了我们就不重建了,只是给其赋值。而多文档无论如何都会新建一个视类和框架类文档类,这也就是为什么他是多文档结构的原因。 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ 接下来介绍这个最重要的函数,它基本什么都干了,不管是新建还是打开都得调用它,呵呵…… // CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible) { //下面调用的是CDocTemplate::CreateNewDocument() CDocument* pDocument = CreateNewDocument();//这里面调用了AddDocument(pDocument); //添加了一个CMyMultiTestDoc : public CDocument

MFC常用类-链表类

MFC的链表类 模板类Clist CTypedPtrList 非模板类CObList CPtrList CStringList MFC链表类的常用成员函数——以Clist为例 1.CList(int nBlockSize = 10 ); 2.TYPE GetHead()const; 3.TYPE GetTail()const; 4.RemoveHead() 5.RemoveTail() 6.原型1:POSITION AddHead(ARG_TYPE newElement ); 原型2:void AddHead(CList* pNewList ); 7.原型1:POSITION AddTail(ARG_TYPE newElement ); 原型2:void AddTail(CList* pNewList ); 8.RemoveAll() 9.POSITION GetHeadPosition()const; 10.POSITION GetTailPosition()const; 11.TYPE GetNext(POSITION& rPosition )const; 12.TYPE GetPrev(POSITION& rPosition )const; 13.TYPE GetAt(POSITION position )const; 14.void SetAt(POSITION pos, ARG_TYPE newElement ); 15.void RemoveAt(POSITION position ); 16.POSITION InsertBefore(POSITION position, ARG_TYPE newElement ); 17.POSITION InsertAfter(POSITION position, ARG_TYPE newElement ); 18.POSITION Find(ARG_TYPE searchValue, POSITION startAfter = NULL)const; 19.POSITION FindIndex(int nIndex )const; 20.int GetCount()const; 21.BOOL IsEmpty()const; 例题 struct CStudent { CString m_strName; int m_nScore; }; CPtrList m_List; 向添加链表中添加元素 CStudent* m_pStudent = new CStudent; m_pStudent->m_strName = m_strName; m_pStudent->m_nScore = m_nScore; m_List.AddTail(m_pStudent); 删除节点 int nNumber;

(适合初学者)MFC基础教程

Visual C++/MFC初学教程 目录 +-- 第一章 VC入门 |------ 1.1 如何学好VC |------ 1.2 理解Windows消息机制 |------ 1.3 利用Visual C++/MFC开发Windows程序的优势 |------ 1.4 利用MFC进行开发的通用方法介绍 |------ 1.5 MFC中常用类,宏,函数介绍 +-- 第二章图形输出 |------ 2.1 和GUI有关的各种对象 |------ 2.2 在窗口中输出文字 |------ 2.3 使用点,刷子,笔进行绘图 |------ 2.4 在窗口中绘制设备相关位图,图标,设备无关位图 |------ 2.5 使用各种映射方式 |------ 2.6 多边形和剪贴区域 +-- 第三章文档视结构 |------ 3.1 文档视图框架窗口间的关系和消息传送规律 |------ 3.2 接收用户输入 |------ 3.3 使用菜单 |------ 3.4 文档,视,框架之间相互作用 |------ 3.5 利用序列化进行文件读写 |------ 3.6 MFC中所提供的各种视类介绍 +-- 第四章窗口控件 |------ 4.1 Button |------ 4.2 Static Box |------ 4.3 Edit Box |------ 4.4 Scroll Bar |------ 4.5 List Box/Check List Box |------ 4.6 Combo Box/Combo Box Ex |------ 4.7 Tree Ctrl |------ 4.8 List Ctrl |------ 4.9 Tab Ctrl |------ 4.A Tool Bar |------ 4.B Status Bar |------ 4.C Dialog Bar |------ 4.D 利用AppWizard创建并使用ToolBar StatusBar Dialog Bar |------ 4.E General Window

MFC常用类-CTimeSpan类

CTimeSpan类 1.构造函数。 CTimeSpan类有下列构造函数: (1)CTimeSpan(); (2)CTimeSpan(const CTimeSpan& timeSpanSrc ); (3)CTimeSpan(time_t time ); (4)CTimeSpan(LONG lDays, int nHours, int nMins, int nSecs ); 参数timeSpanSrc为一个已存在的CTimeSpan 对象,time为一个time_t 类型的时间值,lDays, nHours, nMins, nSecs分别为天数、小时数、 分数和秒数。 2.时间值的提取函数 (1)GetDays()获得CTimeSpan类对象中包含的完整的天数。 (2)GetHours()获得当天的小时数,值在-23到23之间。 (3)GetTotalHours()获得CTimeSpan类对象中包含的完整的小时数。 (4)GetMinutes()获得当前小时包含的分数,值在-59到59之间。 (5)GetTotalMinutes()获得CTimeSpan类对象中包含的完整的分数。 (6)GetSeconds()获得当前分钟包含的秒数,值在-59到59之间。 (7)GetTotalSeconds()获得CTimeSpan类对象中包含的完整的秒数。 格式化时间 Format()将一个CTimeSpan对象转换成格式字符串。使用方式与CTime类似,格式化字符包括以下几个: %D: CTimeSpan的总天数; %H:不足整天的小时数; %M:不足1小时的分数; %S:不足1分钟的秒数; %%:百分号。 4.重载运算符 CTimeSpan类也重载了运算符“=”,“+”,“-”,“+=”,“-=”,“==”,“!=”,“<”,“>”,“<=”,“>=”,用于CTimeSpan对象的赋值、加减运 算及两个CTimeSpan对象的比较。 例子代码 构造一个CTimeSpan对象,并获取其中的完整天数、小时数、分数和秒数,将获得的信息在信息框中显示。 CTimeSpan m_timespan(3,4,5,6); // 3天,4小时,5分,6秒 LONG m_totalDays=m_timespan.GetDays(); //获得完整天数 LONG m_totalHours=m_timespan.GetTotalHours(); //获得完整小时数 LONG m_totalMinutes=m_timespan.GetTotalMinutes(); //获得完整分数 LONG m_totalSeconds=m_timespan.GetTotalSeconds(); //获得完整秒数 char s1[8], s2[8], s3[8], s4[8]; wsprintf(s1,"%ld",m_totalDays); wsprintf(s2,"%ld",m_totalHours); wsprintf(s3,"%ld",m_totalMinutes); wsprintf(s4,"%ld",m_totalSeconds); CString m_str = "此时间范围包含:\n完整天数:"+CString(s1)+"\n完整小时数:"+CString(s2)+"\n完整分数:"+CString(s3)+"\n完整秒 数:"+CString(s4); MessageBox(m_str);

MFC类库的基本类

MFC类库是一个层次结构,主要有CObject类、应用程序类、可视对象类、绘图和打印类、通用类、数据库类、Internet和网络类、OLE类。 (1)CObject类 CObject类是MFC的抽象基类,MFC中的大多数类是从CObject类派生出来的。它是MFC 中多数类和用户自定义的根类,该类为程序员提供了希望融入所编写程序的许多公共操作,包括对象的建立和删除、串行化支持、对象诊断输出、运行时信息以及集合类的兼容等。CObject类的声明在Afx.h中。 (2)应用程序结构类 该类主要用于构造框架应用程序的结构,提供了多数应用程序公用的功能.编写程序的任务是填充框架,添加应用程序专有的功能。 1.应用程序和线程支持类 CWinThread类是所有线程的基类,窗口应用程序类CWinApp类就是从该类中派生来的。每个应用程序有且只有一个应用程序对象,在运行程序中该对象和其他对象相互协调,该对象从CWinApp中派生出来。该类封装了初始化、运行、终止应用程序的代码。 2.命令相关类 CCmdTarget类是CObject的子类,它是MFC所有具有消息映射属性的基类。消息映射规定了当一对象接收到消息命令时,应调用哪个函数对该消息进行处理。程序员很少需要从CCmdTarget类中直接派生出新类,往往都是从它的子类中派生出新类。如窗口类(CWnd)、应用程序类(CWinApp)、文档模板类(CDocTemplate)、视类(CView)及框架窗口类(CFrameWnd)等。 3.文档类 文档对象由文档对象模板创建,用于管理应用程序的数据。视图对象表示一个窗口的客户区,用于显示文档数据并允许读者与之交互。有关文档/视结构的类如下: ①CDocTemplate类:文档模板的基类。文档模板用于协调文档、视图和框架窗口的创建。 ②CSingleDocTemplate类:单文档界面(SDI)的文档模板。 ③CMultiDocTemplate类:多文档界面(MDI)的文档模板。 ④CDocument类:应用程序专用文档的基类。 (3)可视对象类 1. CWnd类 该类提供了MFC中所有窗口类的基本功能。它是CCmdTarget类的子类。创建Windows窗口要分两步进行:首先,引入构造函数,构造一个CWnd对象;然后调用Creat建立Windows 窗口并将它连到CWnd对象上。MFC中还从CWnd类派生出了进一步的窗口类型,以完成更具体的窗口创建工作,这些派生类有: ①CFrameWnd类:SDI应用程序主框架窗口的基类。 ②CMDIFrameWnd类:MDI应用程序主框架窗口的基类。 ③CMDIChildFrameWnd类:应用程序文档框架窗口的基类。 2. CView类 使用CView类(视图类)可以在其他窗口中创建子窗口,它可以提供一个特殊的接受外来输入的结构窗口。也就是说,CView类用于控制用户如何观看文档的数据,以及怎样与这些数据交互。即CView类管理着框架窗口的客户区,为用户与Windows之间提供可视接口。该类接收来自用户的键盘或鼠标的输入,还允许用户对数据进行预览和打印。 CView类广泛应用于基于文档的应用程序中。利用该类的派生类,可图形化地管理文档数据,用户对文档的操作都是通过它来实现的。CView类可用来实现用户自定义视图类的基本功能。在程序运行时,CView类用于视图的实现。一个视图只能分配给一个文档,但一个文档

MFC常用类-CPoint,CRect,CSize类

CPoint类 类CPoint是对Windows结构POINT的封装,凡是能用POINT结构的地方都可以用CPoint代替。 结构POINT表示屏幕上的一个二维点,其定义为: typedef struct tagPOINT{ LONG x; LONG y; } POINT; 其中x、y分别是点的横坐标和纵坐标。 由于CPoint提供了一些重载运算符,使得CPoint的操作更加方便。如运算符“+”,“-”,“+=”和“-=”用于两个CPoint 对象或一个CPoint对象与一个CSize对象的加减运算,运算符“==”和“!=”用于比较两个CPoint对象是否相等。 CSize类 类CSize是对Windows结构SIZE的封装,凡是能用SIZE结构的地方都可以用CSize代替。 结构SIZE表示一个矩形的长度和宽度,其定义为: typedef struct tagSIZE{ LONG cx; LONG cy; } SIZE; 其中cx、cy分别是长度和宽度。 与CPoint类似,CSize也提供了一些重载运算符。如运算符“+”,“-”,“+=”和“-=”,用于两个CSize对象或一个CSize对象与一个CPoint 对象的加减运算,运算符“==”和“!=”用于比较两个CSize对象是否相等。 由于CPoint和CSize都包含两个整数类型的成员变量,他们可以进行相互操作。CPoint对象的操作可以以CSize对象为参数。同样,CSize 对象的操作也可以以CPoint对象为参数。如可以用一个CPoint对象构造一个CSize对象,也可以用一个CSize对象构造一个CPoint对象, 允许一个CPoint对象和一个CSize对象进行加减运算。 CRect类 类CRect是对Windows结构RECT的封装,凡是能用RECT结构的地方都可以用CRect代替。 结构RECT表示一个矩形的位置和尺寸,其定义为: typedef struct tagRECT{ LONG left; LONG top; LONG right; LONG bottom; } RECT; 其中left、top分别表示矩形左上角顶点的横坐标和纵坐标,right、bottom分别表示矩形右下角顶点的横坐标和纵坐标。 由于CRect提供了一些成员函数和重载运算符,使得CRect的操作更加方便。 1.CRect的构造函数 CRect有如下6个构造函数: CRect(); CRect(int l, int t, int r, int b ); CRect(const RECT& srcRect ); CRect(LPCRECT lpSrcRect ); CRect(POINT point, SIZE size );

MFC常用控件用法

MFC 常用整理 MFC USUAL TRIM 艾德温*范克里夫 学生所在学院:信息科学与工程学院 学生所在班级:软件2班 学生姓名:王海波 学生学号:110120010061 指导教师:王海波 教务处 2014年 7 月

目录 MFC 常用知识 第一回:整体感知 第二回: MFC是什么 第三回:开始用MFC创建窗体以及MFC的结构第四回: VS2010界面组织 MFC 常用控件写法 常用控件介绍 常用控件使用 按钮的使用 编辑框的使用 选项卡的使用 报表的使用

MFC 常用知识 第一回: 想写一个像上图(大二写的的吧。。囧)的窗体程序,我们就可以用简单的MFC.怎么用MFC做出上图的窗体? 1 如下图用vs2010的可视化工具栏拖控件,很简单

2 然后双击某个按钮,vs2010会自动弹出函数,我们就可以在函数中填写代码。之后,每当你按那个按钮一次,你在函数中写的代码就会执行一次。 3 显然这一点功能远远不够,更多请看下回。

第二回: 回顾:第一回讲的就是一个窗体初级的原型。接下来说说更深一点的东西。 MFC 是什么?(上面的窗体等是哪里来的?) 定义:MFC: Microsoft function class (微软功能类) 理解:MFC 就是许许多多的类。 跟我们有什么联系:我们利用MFC中的许多类作为工具来开发出窗体。 更浅显的理解:MFC就是工具,让我们能快速开发的工具。之前穆云峰老师的windows编程课记着么,最开始窗体就是那么一句句代码手动写出来的,特繁琐,所以微软就写了功能封装类,把一些重复的工作写成类,之后写窗体就更方便了。 第三回: 一:开始用MFC 写窗体 1 2

MFC中常用函数

1.IsEmpty() 函数判断一对象是否初始化,返回布尔值. 表达式 IsEmpty(expression) 实例: <% Dim i response.write IsEmpty(i) %> 返回结果: true 2. GetAt 函数原型:TCHAR GetAt( int nIndex ) const; 函数返回值:字符中第nIndex个字符(从0开始). Header: atlcoll.h 注意:nIndex的最大值可由GetUpperBound()得到。若nIndex小于0或大于最大值,将返回错误。 3. isdigit isdigit 原型:extern int isdigit(char c); 用法:#include 功能:判断字符c是否为数字 说明:当c为数字0-9时,返回非零值,否则返回零。 附加说明此为宏定义,非真正函数。

相关函数: isalnum,isalpha,isxdigit,iscntrl,isgraph,isprint,i spunct,isspace 4. isalnum 原型:extern int isalnum(int c); 用法:#include 功能:判断字符变量c是否为字母或数字 说明:当c为数字0-9或字母a-z及A-Z时,返回非零值,否则返回零。 5. isalpha 函数:isalpha 原型:int isalpha(int ch) 用法:头文件加入#include (旧版本的编译器使用) 功能:判断字符ch是否为英文字母,当ch为英文字母a-z或A-Z时,在标准c中相当于使用 “isupper(ch)||islower(ch)”做测试,返回非零值,否则返回零。 PS:{ isupper 原型:extern int isupper(int c);

C _MFC快速超简单入门

C++MFC快速超简单入门学习 注意:红色字体为重要的信息,必须理解并记住。 在学习MFC之前,你必须对C++的“类和对象有一定的认识和理解,因为MFC就是C++完全的面向对象设计,它里面封装了好多类,我们只要调用就OK,就像C语言调用库函数一样,直接使用,这就是C++ 第一特性:封装性,第二性就是继承与派生, 这个在MFC中体现得淋淋至间(字打错了)。如果不懂,我再来解释一下,例:有一个商品类,class GOODS商品属性有名字,价格 它可作为一个基类,我可以派上出苹果类,class Apple:public GOODS.苹果属性出了继承了商品的属性名字,价格之外,还可派生出,颜色,等属性,继承与派生就是一个是另一个的子集,但是这个子集不仅包括父集的特征,还具有一些新的特性,懂了吧,这样。MFC其中重要的类是:CDialog对话框类,CEdit,(编辑框 类)CButton,(按钮类)CRadio(单选钮类),这些都是作为基类,由我们自己定义的类去派生它们。 好了,现在先了解一下什么是MFC吧,请看当前目录下的MFC入门知识的幻灯片1—20张,或大概的浏览一下当前目录下的其它连个word文件,后面的幻灯片我觉得没必要看了,因为是快速吗,节约时间,(首先看不懂没关系,)但但看完之后,必须掌握如下知识: 1.MFC是作什么用的?与以前我们写的C,C++语言有什 么不同。以及它的一些优点, 不同,以前的是控制台的界面不好看,不友好,操作不 方便,黑框框的一片。 MFC反之。 优点:可用极少的代码实现强大的功能, 2.关于MFC的一些术语,概念啊

3.你要知道MFC的对话框是由控件组成的,具有 哪些控件(例按钮:Button,单选钮:radio,Edit)例:要知道MFC的编程的原则,也就是宗旨理念吧,“消息映射,事件驱动“,这句话要记住并理解,很重要,真的。那到底是什么意思呢? 现实举例:一个人具备一种“感知“的能力,(也可称消息吧),当用火接近这个人时(发生的事件),就会(驱动)这个人做出反应,远离”火“, 用MFC举例:一个按钮有什么消息啊,我可以单击它,所以它具备单击的消息: 第一个就是左键单击的消息,第二个 就是双击的消息,见名思议就OK了。我单击这个按钮要产生某个事件, 我就可以第一步,先给按钮添加一个消息响应函数,意思就是当我单击按钮时,就调用那个函数,按钮时时刻刻都处于待命的状态, 假如添加的函数如下: void CDsDlg::OnButton1() { AfxMessageB ox(“我单击了这个按钮”);

MFC常用类-CTime类

CTime类 1.构造和初始化CTime类对象 CTi me类有下列构造函数: CTi me(); CTi me(const CTi me& timeSrc ); CTi me(time_t time ); CTi me(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec, int nDST = -1 ); CTi me(WORD wDosDate, WORD wDosTime, int nDST = -1); CTi me(const SYSTEMTIME& sysTi me, int nDST = -1 ); CTi me(const FILETIME& fileTi me, int nDST = -1); 说明:以不同的方式构造一个CTi me对象。可以用一个已经存在的CTi me对象或一个time_t(在ti me.h中被定义为long)类型变量来构造和初始化CTi me对象,也可以用年、月、日、小时、分、秒来构造和初始化CTi me对象,还可以用SYSTEMTIME、FILETIME结构来构造和初始化CTime对象。SYSTEMTIME、FILETIME结构定义如下: typedef struct _SYSTEMTIME { WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; } SYSTEMTIME; typedef struct _FILETIME { DWORD dwLowDateTime; /* low 32 bits */ DWORD dwHighDateTime; /* high 32 bits */ } FILETIME, *PFILETIME, *LPFILETIME; 2.时间值的提取函数 (1)GetCurrentTime()获取系统当前时间。 原型:static CTi me PASCAL GetCurrentTime(); (2)GetTime()由CTi me对象返回一个time_t变量。 原型:time_t GetTime()const; (3)GetYear()获取CTime对象代表的年。 原型:int GetYear()const; 以下(4)至(9)函数原型与GetYear()类似。 (4)GetMonth()获取CTi me对象代表的月。 (5)GetDay()获取CTi me对象代表的日期。 (6)GetHour()获取CTi me对象代表的小时。 (7)GetMinute()获取CTi me对象代表的分。 (8)GetSecond()获取CTime对象代表的秒。 (9)GetDayOfWeek()获取CTi me对象代表的星期几,1代表周日、2代表周一、等等。

相关文档