MFC消息映射学习笔记

来源:互联网 发布:模拟飞行软件 编辑:程序博客网 时间:2024/05/17 06:42

事件和消息

一、消息就是用于描述某个事件发生的信息,而事件是对于Windows的某种操作。

二、事件和消息密切相关,事件是因,消息是果,事件产生消息,消息对应事件。所谓消息的响应,其实质就是事件的响应。

三、消息驱动是Windows应用程序的核心,所有的外部响应(如键盘、鼠标和计时器等)都被Windows先拦截,转换成消息后再发送到应用程序中的目标对象,应用程序根据消息的具体内容进行处理。

四、消息不仅可由Windows发出,它也可由应用程序本身或其它程序产生。Windows为每一个应用程序都维护一个或多个消息队列,发送到每个程序窗口的消息都排成一个队列。

消息分类

一、从消息的发送途径上看,可以分为队列消息和非队列消息。

         A、队列消息大都是用户输入的结果,如WM_KEYDOWN和WM_KEYUP、WM_CHAR、                       WM_MOUSEMOVE、WM_LBUTTONDOWN和WM_LBUTTONUP。队列消息还包括时                钟消息(WM_TIMER)、重画消息(WM_PAINT)和退出消息(WM_QUIT)等

         B、非队列消息大部分来自特定的Windows函数,如当调用UpdateWindow时,Windows         将给调用此函数窗口的窗口过程发送WM_PAINT;当调用DestroyWindow时,Windows       将给调用此函数窗口的窗口过程发送WM_DESTROY等

二、从消息的来源来看,可以分为系统消息和自定义消息。

         A、Windows消息是预定义的一些UINT常量值,它对系统本身用到的消息进行了定义

         B、为了实现额外的消息,系统为开发人员预留了消息定义的接口

三、系统消息ID的范围是从0~WM_USER-1,或0X80000~0XBFFFF;应用程序消息从WM_USER(0X0400)~0X7FFF,或0XC000~0XFFFF;WM_USER~0X7FFF范围的消息由应用程序自己使用;0XC000~0XFFFF范围的消息用来和其他应用程序通信,为了保证ID的唯一性,使用::RegisterWindowMessage来获取该范围的消息ID

四、从对消息的处理上看,可以分为窗口消息、命令消息和控件通知。

         A、窗口消息(WindowMessage)是由操作系统和控制其他窗口的窗口所使用的消息, 它一般与窗口的内部运作有关,如创建窗口、绘制窗口和销毁窗口等

         B、命令消息是一种特殊的窗口消息,它从一个窗口发送到另一个窗口,以处理来自用  户的请求。当用户单击一个菜单项、工具栏或者使用加速键时,将会产生命令消息,并     被发送到能处理该请求的类对象

         C、控件通知类似于命令消息,当用户与控件窗口交互时,这一类消息就从控件窗口发  送到其主窗口

 

消息发送

一、发送消息到一个窗口可以采用传送(Send)或寄送(Post)方式,这两种方式之间的主要区别是消息被接收对象收到后是否立即被处理。

二、Windows提供了三个API函数用于消息的发送

         A、SendMessage函数用于向一个或多个窗口传送消息,该函数将调用目标窗口的窗口   函数,直到目标窗口处理完收到的消息,该函数才返回。

         B、PostMessage函数用于向一个或多个窗口寄送消息,它把消息放在指定窗口创建的   线程的消息队列中,然后不等消息处理完就返回。

         C、SendDlgItemMessage函数函数用于向对话框中指定的控件发送消息,直到目标控件 处理完收到的消息,该函数才返回。

三、三个函数拥有相同的参数:

         HWNDhWnd,      // handle to destinationwindow

         UINTMsg,       // message

         WPARAMwParam,  // first message parameter

         LPARAMlParam   // second message parameter

四、MFC将这三个函数封装为CWnd窗口类的成员函数,封装了目标窗口句柄(不需要hWnd这个参数),它们将向调用它的窗口对象发送或寄送消息,

五、与用户输入相关的消息(如鼠标消息和键盘消息)通常是以寄送(Post)的方式发送,以便这些用户输入可以由运行较缓慢的系统进行缓冲处理。而其它消息通常是以传送(Send)的方式发送

 

消息映射(Message Map)

一、消息映射机制,指MFC类中将消息与消息处理函数联系起来,一一对应的机制。

二、从类CCmdTarget派生的类理论上均可处理消息

三、映射一个消息的过程由三个部分组成:

         A、在处理消息的类中,使用消息宏DECLARE_MESSAGE_MAP()声明对消息映射的支持,         并在该宏之前声明消息处理函数。

         B、使用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏在类声明之后的地方定义该类  支持的消息映射入口点,所有消息映射宏都添加在这里

         C、定义消息处理函数

四、为了使该消息能被其他对象接收并处理,在函数中常常需要调用基类中的相关消息处理函数

//利用ClassWizard为框架类添加消息WM_CLOSE、

//WM_DESTROY及菜单项“Edit|Copy”的消息处理函数,分析

//ClassWizard完成了哪些工作

//消息映射宏如下:

BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)  

         //{{AFX_MSG_MAP(CMainFrame)

         ON_WM_CREATE() 

         //由MFCAppWizard程序向导自动生成的消息映射

         ON_WM_CLOSE()    // 由ClassWizard类向导添加

             ON_WM_DESTROY()

             ON_COMMAND(ID_EDIT_COPY, OnEditCopy)

             //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

//ClassWizard在类的定义中声明了消息处理函数

class CMainFrame : CFrameWnd

{

public:

     CMainFrame();

protected:

     //{{AFX_MSG(CMainFrame)       // 声明消息处理函数原形

     afx_msg  intOnCreate(LPCREATESTRUCT lpCreateStruct); 

                                               //由程序向导自动生成

     afx_msg  void  OnClose();  // 由ClassWizard类向导添加

     afx_msg  void  OnDestroy();

     afx_msg  void  OnEditCopy();

     //}}AFX_MSG

     DECLARE_MESSAGE_MAP()  // 声明使用消息映射宏

};

 

MFC

一、宏就是用预处理指令#define定义一个标识符,用它来表示一个字符串或一段源代码。MFC宏作为MFC类库的一个组成部分在MFC应用程序中经常出现。MFC宏在Afxwin.h、Afx.h及Afxmsg_.h等MFC头文件中分别进行了定义。

二、MFC提供的宏有很多,常用的包括消息映射宏、运行时类型识别的宏、调试宏和异常宏等


消息传递

手工处理消息映射

一、由于程序逻辑设计结构的限制或不同窗口之间数据的同步,程序员需要手工自定义一些消息。例如,如果需要在特定时间间隔内通知所有数据输出窗口重新取得数据,就必须采用定时器事件来产生特定的消息。

二、MFC允许用户自定义消息,常量WM_USER(为0x0400)与第一个自定义消息值相对应,用户必须为自己的消息定义相对于WM_USER的偏移值,。利用#define语句定义自己的消息,例如:

         #define  WM_USER1 WM_USER+0

         #define  WM_USER2 WM_USER+1

三、自定义消息处理函数的声明:

         A、必须在函数返回类型前面加上afx_msg标识,如:afx_msg  LRESULT  memberFxn   (WPARAM  wParam , LPARAM  lParam);

         B、参数wParam、lParam用于传递消息的两个附加信息

四、自定义消息映射宏的定义:

         A、ON_MESSAGE(message,memberFxn)。其中,message是消息名标识,memberFxn是  对应的消息处理函数。如:ON_MESSAGE(WM_MYMESSAGE,OnMyMessage)

鼠标消息

一、用户移动鼠标时,系统屏幕上移动一个称之为鼠标光标的位图。鼠标光标含有一个叫做热点的像素点,系统用它来跟踪和识别光标的位置。

二、用户移动鼠标,按下或释放鼠标,鼠标将会产生一个输入事件。Windows系统把鼠标事件转换为消息,再把它们投递到线程消息队列中。

三、根据用户操作鼠标时鼠标的位置,鼠标消息分为二大类:

         A、用户区鼠标消息:当鼠标光标位于程序窗口的用户区时,将生成客户区鼠标消息。

         B、非客户区鼠标消息:非客户区包括标题栏、最小和最大化按钮、关闭窗口按钮、系  统菜单栏和窗口框架等。非客户区鼠标消息一般由VC进行处理。

处理客户区鼠标消息

以上消息处理函数的参数都是相同,例如:afx_msg  void OnMouseMove(UINT nFlags, CPoint point );

 

一、nFlags参数:包含额外的鼠标键和键盘键的信息,以指出发生消息时某些鼠标键与键盘键的状态,可能的取值为:

         A、MK_CONTROL   键盘上的Ctrl键被按下

         B、MK_LBUTTON   鼠标左键被按下

         C、MK_MBUTTON 鼠标中键被按下

         D、MK_RBUTTON  鼠标右键被按下

         E、MK_SHIFT           键盘上的Shift键被按下

二、在鼠标消息处理函数内,可用按位逻辑“与”运算检测特定键的信息,如下:

         A、if(nFlags& MK_SHIFT)   //结果若为非零值,表示键被按下

         B       MessageBox("鼠标事件发生时,Shift键被按下!");

三、point参数:包含鼠标指针的坐标位置,其类型为CPoint类,CPoint类是MFC预定义的用来描述点的类,其包含二个数据成员,point.x内为鼠标指针的横坐标,point.y内为鼠标指针的纵坐标。

 

捕捉鼠标

一、由于鼠标的随机性,用户可能在一个应用程序的窗口内按下鼠标左键,而移动到另一个应用程序的窗口内后释放鼠标左键,这样第一个应用程序只能收到WM_LBUTTONDOWN消息,而第二个应用程序只能收到WM_LBUTTONUP消息。比如一个用鼠标绘图的程序会造成混乱。

二、为使所有鼠标消息均定向到某一窗口,而不管鼠标光标位于何处,就必须对鼠标加以捕捉。下面列出了与捕捉鼠标有关的两个函数

         A、CWnd::SetCapture()函数:用于捕捉鼠标

         B、CWnd::ReleaseCapture():函数用于释放对鼠标的捕捉

 

鼠标绘图代码

//工程名称为Draw,单文档

void CDrawView::OnMouseMove(UINT nFlags,CPoint point) {

         if(nFlags& MK_LBUTTON){     //若左键按下

                   CDC*pDC=GetDC();        //取得客户区设备描述符表

                   pDC->SetPixel(point,RGB(255,0,0));  //在鼠标所指位置画点,红色

                   ReleaseDC(pDC);              //释放客户区设备描述符表

         }

         elseif(nFlags & MK_RBUTTON){     //若右键按下

                   CDC*pDC=GetDC();       //取得客户区设备描述符表

                   pDC->SetPixel(point,RGB(255,255,255));

                   //用白色在鼠标所指位置画点,即擦除原有点

                   ReleaseDC(pDC);              //释放客户区设备描述符表

         }

         CView::OnMouseMove(nFlags,point);

}

光标

一、光标(Cursor)是一种特殊的、可移动的32×32点阵图形,它是用来作为鼠标指针的图形标志。

二、光标与图标最大的区别是光标有一个热点,用于确定光标当前的像素位置。利用光标资源编辑器可以重新设置光标的热点,如图所示,光标资源编辑器的右上部有一个热点设置按钮“*á”,单击这个按钮,在光标编辑区会出现一个十字光标,将十字光标的中心放在要设定热点的位置,单击鼠标就可以设置光标的热点。

 

改变光标的形状

一、光标形状的变化代表了程序当前状态的改变。不需要用户专门处理,Windows就支持三种最普通的光标:箭头(正常情况)、沙漏(应用程序忙)和I形光标(光标超出程序窗口或进行文本输入。

二、MFC类CCmdTarget提供成员函数BeginWait- Cursor()、EndWaitCursor()和RestoreWaitCursor()用于改变光标的状态。

三、光标与图标一样,MFC也没有提供对应的类,一般采用句柄的方式使用光标

void CWaitCurView::OnLButtonDown(UINT nFlags,CPoint point)

{

         //TODO: Add your message handler code here . . .

         SetCapture();

         BeginWaitCursor(); // 显示沙漏状光标

         SetTimer(1,2000,NULL);//启动一个2秒的计时器

         CView::OnLButtonDown(nFlags,point);

}

void  CWaitCurView::OnTimer(UINT nIDEvent) // 2秒后调用该消息处理函数

{

         //TODO: Add your message handler code here . . .

         ReleaseCapture();

         EndWaitCursor();     // 2秒后恢复光标原来的形状

         KillTimer(1);               // 删除计时器

         CView::OnTimer(nIDEvent);

}

 

添加光标

一、首先利用Insert|Resource菜单命令添加和编辑Cursor光标资源,然后通过调用CWinApp:: LoadCursor()加载光标。加载成功后,调用函数SetCursor()设置光标。

二、一般在WM_SETCURSOR的消息处理函数OnSet- Cursor()中重新设置光标。

三、用户也可以直接使用Windows系统提供的光标,首先需要调用CWinApp::LoadStandardCursor()来加载,通过不同的参数加载不同的系统光标。如:IDC_ARROW、IDC_IBEAM、IDC_WAIT、IDC_CROSS、IDC_UPARROW。

 

//添加一个ID为IDD_MYDLG、标题为“使用系统光标”的对话框

//资源和对话框类CMyDlg。利用ClassWzard添加消息

//WM_SETCURSOR的处理函数:

BOOL CMyDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)

{

     // TODO: Add your message handler code here  . . .

         HCURSOR  hcursor;

         hcursor=AfxGetApp()->LoadStandardCursor(IDC_SIZEALL);

         //加载系统光标

         //hcursor=AfxGetApp()->LoadCursor(IDC_HAND);

         //加载自定义光标

         SetCursor(hcursor);

         return  TRUE;                  //return CDialog::OnSetCursor . . .

}

 

与键盘有关的概念

一、焦点

         A、键盘由多个应用程序共享,但当在键盘上按下一个键时,只有一个窗口能接收到该  键盘消息。能接收到键盘消息的窗口称为有“输入焦点”的窗口,具有输入焦点的窗口可     能是活动窗口,也可能是活动窗口的子窗口。

         B、当一个窗口获得输入焦点时,Windows向其发送一条WM_SETFOCUS消息,而当其   失去输入焦点时,Windows向其发送WM_KILLFOCUS消息。

二、键盘扫描码与虚拟键代码

         A、键盘上每一个有意义的键都对应着一个唯一的标识值,称为键盘扫描码,键盘扫描  码与具体的键盘硬件有关。为了使应用程序不依赖于具体硬件,Windows系统中还使用     虚拟键代码,它是由Windows系统根据键盘扫描码转换而成的一种标准的键标识符,         对应用程序而言,它与具体设备无关。


键盘消息

一、用户按键会产生键的按下或释放等事件,对这些事件,Windows以键盘消息的形式通知拥有输入焦点的窗口。这些消息还被Windows转换成其它的消息再次发给拥有输入焦点的窗口,例如WM_CHAR

二、系统键(Alt键和其它键的组合)

         A、系统键的功能是激活程序菜单或者系统菜单上的选项、以及切换活动窗口等系统功  能。这类消息一般由Windows系统内部直接处理,而应用程序不必处理。

         B、WM_SYSKEYDOWN,WM_SYSCHAR,WM_SYSKEYUP

三、非系统键(非Alt键和其它键的组合)

         A、WM_KEYDOWN,WM_CHAR,WM_KEYUP

键盘消息处理函数

一、OnKeyDown()和OnKeyUp()这两个参数相同,例如:afx_msg void OnKeyDown( UINT nChar, UINTnRepCnt, UINTnFlags );

二、参数含义:

         A、nChar:键的虚拟码

         B、nRepCnt:重复计数,若应用程序的处理速度慢于用户按键的速度(一般情况下不会   出现这种情况),Windows会把几个WM_KEYDOWN或WM_KEYUP消息合并到单个消息        中,并相应增加重复计数

         C、nFlags:提供一些特殊信息,按位使用

三、OnChar函数的原型:afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINTnFlags);

四、参数含义:

         A、nChar:键码(ASCII码)

         B、nRepCnt:按键重复次数,同OnKeyDown与OnKeyUp函数的这一参数。

         C、nFlags:提供一些特殊信息,按位使用

键盘事件的处理原则

一、WM_CHAR消息通常是最有用的消息,它的消息参数中包含可显示字符的ASCII码,能区分字母的大小写,但不能处理非显示字符,如键盘上的“→”“←”“↓”“↑”键。

二、WM_KEYDOWN和WM_KEYUP的消息参数中包含键的虚拟码,它可处理非显示字符,但虚拟键不区分大小写字母。如果需要在这二个消息中处理字母的大小写问题,需要使用API函数GetKeyState()获得Shift键和CapsLock键的状态,才能判定是大写字母还是小写字母。

三、通常需要处理可显示字符时响应WM_CHAR消息,Enter、Backspace、Escape等键也可在WM_CHAR消息中处理。当要处理非显示字符时响应WM_KEYDOWN和WM_KEYUP消息,比如要读取光标键、功能键、Delete键、Insert键、shift键、Ctrl键、Alt键等。

 

0 0
原创粉丝点击