|
楼主 |
发表于 2006-1-13 10:56:19
|
显示全部楼层
<>2.4.4 MFC对消息的管理<BR><BR>Windows消息的管理包括消息发送和处理。为了支持消息发送机制,MFC提供了三个函数:SendMessage、PostMessage和SendDlgItemMessage。而消息处理则相对来说显得复杂一些。MFC采用了一种新的机制取代C语言编程时对Windows消息的Switch/Case分支,简化了Windows编程,使程序可读性、可维护性大大提高。<BR><BR>MFC对消息的处理<BR><BR>MFC不使用用C语言编写Windows程序时用的易产生错误的switch/case语句,而采用一种消息映射机制来决定如何处理特定的消息。这种消息映射机制包括一组宏,用于标识消息处理函数、映射类成员函数和对应的消息等。其中,用afx_msg放在函数返回类型前面,用以标记它是一个消息处理成员函数。类若至少包含了一个消息处理函数,那么还需要加上一个DECLARE_MESSAGE_MAP()宏,该宏对程序执行部分所定义的消息映射进行初始化。清单2.3演示了消息处理函数的例子:<BR><BR>清单2.3 消息处理函数例子<BR><BR></P>
<>class CMainFrame:CFrameWnd{<BR><BR>public:<BR><BR>CMainFrame();<BR><BR>protected:<BR><BR>//{{AFX_MSG(CMainFrame)<BR><BR>afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);<BR><BR>afx_msg void OnEditCopy();<BR><BR>afx_msg void OnClose();<BR><BR>//}}AFX_MSG<BR><BR>DECLARE_MESSAGE_MAP()<BR><BR>};</P>
<><BR>成员函数OnCreate,OnEditCopy,OnClose分别用来处理消息WM_CREATE、ID_EDIT_COPY和WM_CLOSE。其中,WM_CREATE和WM_CLOSE是系统预定义消息,包含在Windows.h中。而ID_EDIT_COPY是菜单Edit->Copy的标识,也就是用户选择Edit->Copy菜单项时产生的消息,一般在资源文件头文件中定义。在类的实现部分给出这三个成员函数的定义,以及特殊的消息映射宏。上面的例子的消息映射宏定义如下:<BR><BR>BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)<BR><BR>ON_WM_CREATE()<BR><BR>ON_COMMAND(ID_EDIT_COPY, OnEditCopy)<BR><BR>ON_WM_CLOSE()<BR><BR>END_MESSAGE_MAP()<BR><BR>消息映射宏由BEGIN_MESSAGE_MAP() 和END_MESSAGE_MAP()。其中,BEGIN_MESSAGE_MAP宏包含两个参数CMainFrame类和CFrameWnd,分别代表当前定义的类和它的父类。在BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()之间,包含了主窗口要处理的各个Windows消息的入口。在本例中,包含三个消息。其中ON_ WM_CREATE被用来指定缺省的成员函数OnCreate与WM_CREATE相对应。在MFC中,包含了大量的预定义消息映射宏,用来指定各种成员函数与各种形如WM_XXXX消息相对应。如ON_WM_CLOSE宏指定了WM_CLOSE消息的处理成员函数为OnClose。这时侯,只需要写出要处理的消息就够了,不必再写出处理函数。消息映射宏ON_COMMAND则被用来将菜单项和用户自定义的命令同它们的处理成员函数联系起来。在上例中,用户选择Edit->Copy菜单项时,系统执行OnEditCopy()函数。ON_COMMAND宏的一般定义形式如下:<BR><BR>ON_COMMAND(command,command_function)<BR><BR>其中,command为菜单消息或用户自定义消息,command_function为消息处理函数。MFC允许用户自定义消息,常量WM_USER和第一个消息值相对应,用户必须为自己的消息定义相对于WM_USER的偏移值,偏移范围在0~0x3FFF之间,这对绝大多数程序来说都是够用的。用户可以利用#define语句直接定义自己的消息:<BR><BR> <BR><BR>#define WM_USER1 (WM_USER+0)<BR><BR>#define WM_USER2 (WM_USER+1)<BR><BR>#define WM_USER3 (WM_USER+2)<BR><BR>下表列出了Windows95中Windows消息值的范围。<BR><BR>常 量 值 消息值范围 意 义 <BR>WM_USER 0x0400 0x0000-0x03FF Windows消息 <BR> 0x0400-0x7FFF 用户自定义的消息 <BR> 0x8000-0xBFFF Windows保留值 <BR> 0xC000-0xFFFF 供应用使用的字符串消息 <BR><BR> <BR><BR>为了说明如何使用用户自定义消息,我们看一个例子,见程序清单2.4:<BR><BR>清单2.4 使用用户自定义消息<BR><BR></P>
<>#include<afxwin.h><BR><BR>#define CM_APPLE (WM_USER+0)<BR><BR>#define CM_ORANGE (WM_USER+1)<BR><BR>class CMainFrame:CFrameWnd{<BR><BR>public:<BR><BR>CMainFrame();<BR><BR>protected:<BR><BR>afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);<BR><BR>afx_msg void OnClose();<BR><BR>//handle user select apple<BR><BR>afx_msg LRESULT CMApple(WPARAM wParam, LPARAM lParam);<BR><BR>//handle user select orange<BR><BR>afx_msg LRESULT CMOrange(WPARAM wParam, LPARAM lParam);<BR><BR>DECLARE_MESSAGE_MAP()<BR><BR>};</P>
<><BR><BR>相应的消息映射如下:<BR><BR>BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)<BR><BR>ON_WM_CREATE()<BR><BR>ON_MESSAGE(CM_APPLE, CMApple)<BR><BR>ON_MESSAGE(CM_ORANGE,CMOrange)<BR><BR>ON_WM_CLOSE()<BR><BR>END_MESSAGE_MAP()<BR><BR>第一个ON_MESSAGE宏用于指定 CM_APPLE 命令消息的处理成员函数为CMApple ,而第二个ON_MESSAGE宏用于指定CM_ORANGE命令消息的处理函数为CMOrange。<BR><BR>消息的发送<BR><BR>Windows应用程序允许应用程序向自己发送消息、向其他应用程序发送消息,甚至可以向Windows操作系统本身发送消息(比如要求关闭操作系统或重新启动操作系统)。Windows提供了三个API函数用于发送消息,这三个函数是:SendMessage、PostMessage和SendDlgItemMessage。<BR><BR>SendMessage用于向窗口发送消息,该函数说明如下:<BR><BR>LRESULT SendMessage(<BR><BR>HWND hWnd, //消息要发往的窗口的句柄<BR><BR>UINT Msg, //要发送的消息<BR><BR>WPARAM wParam, //消息的第一个参数<BR><BR>LPARAM lParam //消息的第二个参数<BR><BR>);<BR><BR>其中,hWnd为接收消息窗口的句柄,参数Msg指定发送的消息,参数wParam和lParam依赖于消息Msg。该函数调用目标窗口的窗口函数,直到目标窗口处理完该消息才返回。<BR><BR>ostMessage函数同SendMessage类似,它把消息放在指定窗口创建的线程的消息队列中,然后不等消息处理完就返回,而不象SendMessage那样必须等到消息处理完毕才返回。目标窗口通过GetMessage或PeekMessage从消息队列中取出并处理。PostMessage函数说明如下:<BR><BR>BOOL PostMessage(<BR><BR>HWND hWnd, //消息发往的窗口<BR><BR>UINT Msg, //要发送的消息<BR><BR>WPARAM wParam, //消息的第一个参数<BR><BR>LPARAM lParam //消息的第二个参数<BR><BR>);<BR><BR> <BR><BR>其中,参数hWnd为接收消息的窗口的句柄,参数Msg指定所发送的消息,参数wParam和lParam依赖于消息Msg。<BR><BR>SendDlgItemMessage函数用于向对话框的某个控制发送消息,函数声明如下:<BR><BR>LONG SendDlgItemMessage(<BR><BR>HWND hDlg, //对话框句柄<BR><BR>int nIDDlgItem, //对话框控件的ID<BR><BR>UINT Msg, //要发送的消息<BR><BR>WPARAM wParam, //消息的第一个参数<BR><BR>LPARAM lParam //消息的第二个参数<BR><BR>); <BR><BR>其中,hDlg为包含目标控制的对话框的窗口句柄,参数nIDDlgItem为接收消息的对话框控制的整数标识符,参数Msg指定了所发送的消息,参数wParam和lParam提供附加的特定消息的信息。<BR><BR>MFC将这三个函数封装为CWnd类的成员函数,隐藏了窗口句柄和对话框句柄。这三个成员函数用于向本窗口发送消息,函数的说明如下:<BR><BR>LRESULT SendMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );<BR><BR>BOOL PostMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );<BR><BR>LRESULT SendDlgItemMessage( int nID, UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );<BR><BR>2.4.5学习MFC的方法<BR><BR>首先要对Windows API有一定的了解,否则无法深入学习MFC。至少要知道Windows对程序员来说意味着什么,它能完成什么工作,它的一些常用数据结构等。<BR><BR>另一点是不要过分依赖于Wizards。Wizards能做许多工作,但同时掩饰了太多的细节。应当看看AppWizard和ClassWizard为你所做的工作。在mainfrm.cpp中运行调试器来观察一下MFC运行的流程。除非你理解了生成的代码的含义,否则无法了解程序是如何运行。<BR><BR>还有很重要的一点就是要学会抽象的把握问题,不求甚解。许多人一开始学习Visual C++就试图了解整个MFC类库,实际上那几乎是不可能的。一般的学习方法是,先大体上对MFC有个了解,知道它的概念、组成、基本约定等。从最简单的类入手,由浅入深,循序渐进、日积月累的学习。一开始使用MFC提供的类时,只需要知道它的一些常用的方法、外部接口,不必要去了解它的细节和内部实现,把它当做一个模块或者说黑盒子来用,这就是一种抽象的学习方法。在学到一定程度时,再可以深入研究,采用继承的方法对原有的类的行为进行修改和扩充,派生出自己所需的类。<BR><BR>学习MFC,最重要的一点是理解和使用MFC类库,而不是记忆。<BR></P> |
|