消息映射编程实验
- 格式:docx
- 大小:130.95 KB
- 文档页数:8
实验十一 MFC的简单消息映射与处理(4学时)[实验目的]1、基本掌握Windows环境下MFC程序的开发流程和方法;2、基本掌握MFC中的消息映射与处理方法;[实验内容]创建一个单文档的MFC工程,使用ClassWizard在视图类中添加WM_KEYDOWN、WM_KEYUP、WM_CHAR键盘消息映射和消息响应函数,添加WM_LBUTTON、WM_ RBUTTON鼠标消息映射和消息响应函数及。
界面如图所示,实现如下功能:程序运行界面图(1)用户按下/释放Shift键时,程序在视图窗口中显示有关的提示信息。
(2)用户按下Shift+B键时,程序在视图窗口中显示有关的提示信息。
(3)用户在视图窗口中按下鼠标左键,并拖动鼠标时,在窗口中绘制一个随鼠标位置变化的椭圆。
当用户释放鼠标键时,停止椭圆的绘制。
[实验步骤](1)创建一个单文档的MFC工程;(2)使用ClassWizard在其视图类中添加键盘消息WM_KEYDOWN、WM_KEYUP和WM_CHAR(分别对应键的按下、松开和按键动作)和消息响应函数;(3)在视图类的头文件中添加成员变量,以记录按键状态:protected:BOOL bShiftdown, bShiftup, bShiftB;并在视图类的构造函数中,对上述成员变量进行初始化:*View::*View(){// TODO: add construction code herebShiftdown=bShiftup=bShiftB=FALSE; //赋初值}其中,红色内容对应VC自动生成部分。
*View为视图类名。
(4)在键盘消息响应函数中,判断按键的状态,并设置上述成员变量的值。
代码如下:void *View::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags){// TODO: Add your message handler code here and/or call default//判断Shift键是否被按下if(nChar==VK_SHIFT){//AfxMessageBox("dd");bShiftdown=TRUE;bShiftup=FALSE;Invalidate(TRUE); //显示信息}CView::OnKeyDown(nChar, nRepCnt, nFlags);}void *View::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags){// TODO: Add your message handler code here and/or call default//判断Shift键是否被释放if(nChar==VK_SHIFT){//AfxMessageBox("dd");bShiftup=TRUE;//显示信息Invalidate(TRUE);bShiftdown=FALSE;}CView::OnKeyUp(nChar, nRepCnt, nFlags);}void *View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags){// TODO: Add your message handler code here and/or call defaultif((nChar==98)||(nChar==66)) //判断是否敲击了字符键B键或b键{if(bShiftdown){bShiftB=TRUE;bShiftdown=FALSE;//显示信息Invalidate(TRUE);}}CView::OnChar(nChar, nRepCnt, nFlags);}(5)对视图类的OnDraw函数进行重载,根据成员变量的值(实际对应着按键的状态),显示相关信息。
#include"my.h"CMyWinApp theApp;//global objectBOOL CMyWinApp::InitInstance(){cout<<"CMyWinApp::InitInstance \n";m_pMainWnd=new CMyFrameWnd;return TRUE;}CMyFrameWnd::CMyFrameWnd(){Create();}BEGIN_MESSAGE_MAP(CMyWinApp,CWinApp)ON_COMMAND(CMyWinAppid,0)END_MESSAGE_MAP()BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd) ON_COMMAND(CMyFrameWndid,0)END_MESSAGE_MAP()BEGIN_MESSAGE_MAP(CMyDoc,CDocument)ON_COMMAND(CMyDocid,0)END_MESSAGE_MAP()BEGIN_MESSAGE_MAP(CMyView,CView)ON_COMMAND(CMyViewid,0)END_MESSAGE_MAP()void printlpEntries(AFX_MSGMAP_ENTRY* lpEntry) {struct{int classid;char* classname;}classinfo[]={CCmdTargetid,"CCmdTarget ",CWinThreadid,"CWinThread ",CWinAppid, "CWinApp ",CMyWinAppid, "CMyWinApp ",CWndid, "CWnd ",CFrameWndid, "CFrameWnd ",CMyFrameWndid,"CMyFrameWnd ",CViewid, "CView ",CMyViewid, "CMyView ",CDocumentid, "CDocument ",CMyDocid, "CMyDoc ",0, " "};for(int i=0;classinfo[i].classid!=0;i++){if(classinfo[i].classid==lpEntry->nID){cout<<lpEntry->nID<<" ";cout<<classinfo[i].classname<<endl;break;}}}void main(){CWinApp* pApp=AfxGetApp();pApp->InitApplication();pApp->InitInstance();pApp->Run();cout<<endl<<endl;CMyDoc* pMyDoc=new CMyDoc;CMyView* pMyView=new CMyView;CFrameWnd* pMyFrame=(CFrameWnd*)pApp->m_pMainWnd;pMyFrame->m_pViewAxtive=pMyView;pMyView->m_pDocument=pMyDoc;cout<<endl<<"pMyFrame received a WM_CREATE,routing path:"<<endl;AfxWndProc(0,WM_CREATE,0,0,pMyFrame);cout<<endl<<"pMyView received a WM_PAINT,routing path:"<<endl;AfxWndProc(0,WM_PAINT,0,0,pMyView);cout<<endl<<"pMyView received a WM_COMMMAND,routing path:"<<endl;AfxWndProc(0,WM_COMMAND,0,0,pMyView);cout<<endl<<"pMyFrame received a WM_COMMAND,routing path:"<<endl;AfxWndProc(0,WM_COMMAND,0,0,pMyFrame);}。
谈谈MFC中的消息映射作者:未知文章来源:网络引言:众所周知,windows是基于消息驱动的,作好消息处理是WINDOWS编程的关键任务之一,用VC制作WINDOWS程式同样离不开消息的处理。
虽然VC++6的类向导可以完成绝大部分工作,但不幸的是,它并不能完成所有的工作。
这就要求我们对 VC中消息的处理有一个比较清淅的认识。
只有这样才可能在必要的时候亲自动手完成一些复杂的消息映射处理。
在MFC中消息是通过一种所谓的消息映射机制来处理的。
其实质是一张消息及其处理函数的一一对应表以及分析处理这张表的应用框架内部的一些程序代码.这样的好处是可以避免像早期的SDK编程一样需要罗列一大堆的CASE语句来处理各种消息.由于不同种类的消息其处理方法是不同的,所以我们有必要先弄清楚 WINDOWS消息的种类。
背景:WINDOWS 消息的种类WINDOWS中消息主要有以下三种类型:1、标准的WINDOWS消息:这类消息是以WM_为前缀,不过WM_COMMAND例外。
例如: WM_MOVE、WM_QUIT等.2、命令消息:命令消息以WM_COMMAND为消息名.在消息中含有命令的标志符ID,以区分具体的命令.由菜单,工具栏等命令接口对象产生.3、控件通知消息:控件通知消息也是以WM_COMMAND为消息名.由编辑框,列表框,子窗口发送给父窗口的通知消息.在消息中包含控件通知码.以区分具体控件的通知消息.其中标准的WINDOWS消息及控件通知消息主要由窗口类即直接或间接由CWND类派生类处理.相对标准WINDOWS消息及控件通知消息而言,命令消息的处理对象范围就广得多.它不仅可以由窗口类处理,还可以由文档类,文档模板类及应用类所处理。
方法:不同种类消息的映射方法。
在以上三种消息中,标准的WINDOWS消息映射是相当简单的。
可直接通过类向导完成不同消息的映射处理,所以不在本文讨论之列。
凡是从CcmdTarget类派生的类都可以有消息映射.消息映射包括如下两方面的内容:在类的定义文件中(.H)中加上一条宏调用:DECLARE_MESSAGE_MAP()通常这条语句中类定义的最后.在类的实现文件(.CPP)中加上消息映射表:BEGIN_MESSAGE_MAP(类名,父类名)………..消息映射入口项.……….END_MESSAGE_MAP( )幸运的是除了某些类(如没有基类的类或直接从CobjectO类派生的类)外.其它许多类均可由类向导生成.尽管生成的类只是一个框架,需要我们补充内容.但消息映射表已经为我们加好了.只是入口项有待我们加入.命令消息映射入口项是一个ON_COMMAND的宏.比如文件菜单下的"打开…"菜单(ID 值为ID_FILE_OPEN)对应的消息映射入口项为:ON_COMMAND(ID_FILE_NEW,OnFileOpen)加入消息映射入口项之后需要完成消息处理函数.在类中消息处理函数都是类的成员函数,要响应一个消息,就必须定义一个该消息的处理函数.定义一个消息处理函数包括以下三方面的内容.1.在类定义中加入消息处理函数的函数原型(函数声明)2.在类的消息映射表中加入相应的消息映射入口项.3.在类的实现中加入消息处理函数的函数体.需要说明的是消息处理函数的原型一定要以afx_msg打头.比如:afx_msg OnFileOpen();// 函数原型作为约定.消息处理函数一般以On打头但有时我们可能想用一个消息处理函数来处理一批消息。
MFC消息映射机制过程1:windows OS事件驱动策略基于3种消息。
标准消息、通告消息、命令消息。
2:“事件”就是“消息”,事件是有形形象的,是站在⼈类能理解的⾓度来定义的。
消息是⽆形抽象的,是站在OS能理解的⾓度来定义的。
3:我把按下⿏标左键这⼀事件转换成WM_LBUTOONDOWN消息来告诉OS我做了按下⿏标左键这了件事情。
现在OS知道了我做了按下⿏标左键这了件事情了,那么OS怎么处理呢?3.1:消息响应函数原型//{{AFX_MSG(CMyView)afx_msg void OnLButtonDown(UINT nFlags,CPoint point);//}}AFX_MSGDECLARE_MESSAGE_MAP()3.2:ON_WM_LBUTTONDOWN消息映射宏BEGIN_MESSAGE_MAP(CMyView, CView)//{{AFX_MSG_MAP(CMyView)ON_WM_LBUTTONDOWN()//}}AFX_MSG_MAP// Standard printing commandsON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)END_MESSAGE_MAP()3.3:消息响应函数的定义void CMyView::OnLButtonDown(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultMessageBox("WM_LBUTTONDOWN");CView::OnLButtonDown(nFlags, point);}4:⾄此,我们从按下⿏标左键到看到如下图的效果,OS完成了对事件做出的反应。
Windows消息的产生:1用户按键或者鼠标操作可以产生消息,如WM_KEYDOWN,WM_LBUTTONDOWN等;2系统可以自己产生消息,如,创建窗口的时候会产生WM_CREATE,WM_TIMER等;3应用程序间可以定义自己的消息,在应用程序间进行消息通讯;Windows消息的分类:Windows消息的分类1.标准消息(除WM_COMMAND 外的WM_消息)从CWnd派生的类可接收该消息2.命令消息(以WM_COMMAND 形式出现)菜单,快捷键,工具条按钮消息,从CCmdTarget派生的可以接收3.通告消息: 控件产生的消息(按钮等),从CCmdTarget派生的可以接收从CWnd派生的类可接收3种消息,从CCmdTarget派生接收2,34. 用户自定义消息:为了跟系统消息区分,系统专门划分一段消息编号区间来让用户定义自己的消息。
#define MY_MESSAGE WM_USER + 1 // 用户自定义消息菜单命令路由:消息传递:1框架2视类消息处理:1视类2视类传给文档类3文档类传回视类,再传给框架4应用程序类Windows32消息的结构:MSG 结构的定义如下:typedef struct tagMSG{HWND hwnd; //接收消息的窗口句柄UINT message; //消息标识(ID)WPARAM wParam; //第一个消息参数LPARAM lParam; //第二个消息参数DWORD time; //消息产生的时间POINT pt; //消息产生时鼠标的位置} MSG;回忆窗口处理函数首部,主消息循环相关重要代码。
MFC消息处理机制:所谓消息映射,简单地讲,就是让程序员指定要某个MFC类(有消息处理能力的类)处理某个消息。
MFC提供了工具ClassWizard来帮助实现消息映射,在处理消息的类中添加一些有关消息映射的内容和处理消息的成员函数。
程序员将完成消息处理函数,实现所希望的消息处理能力。
基于mfc的实验报告摘要本实验旨在通过使用MFC(Microsoft Foundation Classes)开发框架,实现一个简单的图形化界面程序。
通过这次实验,我深入理解了MFC框架的基本原理和开发流程,并成功完成了一个简单的图形化界面程序。
1. 引言MFC是微软公司开发的一套C++类库,用于创建Windows平台上的应用程序。
它建立在Windows API之上,简化了Windows操作系统的编程方式。
MFC 提供了一系列的类和函数,包括窗口(Window)、对话框(Dialog)、消息映射(Message Map)等,极大地简化了Windows应用程序的开发过程。
2. 实验目的本实验主要目的是熟悉MFC框架的基本原理和开发流程,实现一个简单的图形化界面程序。
通过本实验,能够掌握MFC框架中的窗口创建、消息处理、界面设计等基本概念和操作。
3. 实验过程3.1 环境配置首先,需要在计算机上安装Visual Studio和MFC组件。
打开Visual Studio,创建一个新的MFC应用程序项目,并选择对话框类型作为项目的基础结构。
3.2 窗口创建在MFC应用程序中,窗口是最基本的界面单位。
通过菜单选择“添加类”的方式,创建一个新的对话框类,并继承自CDialog类。
在新建的对话框类中,可以定义与界面相关的成员变量和控件。
3.3 控件添加在对话框设计界面中,可以通过拖拽和调整控件的方式,向对话框中添加各种控件,如按钮、文本框、列表框等。
每个控件都有自己的属性和事件响应函数。
3.4 消息映射消息映射是MFC框架的核心概念之一。
通过消息映射,可以将用户的操作(如点击按钮)与特定的函数关联起来。
在对话框类中,可以通过DECLARE_MESSAGE_MAP和BEGIN_MESSAGE_MAP宏定义来实现消息映射关系的建立。
3.5 编译和运行完成界面设计和消息映射后,即可对程序进行编译和运行。
在编译过程中,MFC 会自动将资源文件编译成可执行的文件。
MFC教程(4)-- 消息映射的实现(1)消息映射的实现Windows消息概述Windows应用程序的输入由Windows系统以消息的形式发送给应用程序的窗口。
这些窗口通过窗口过程来接收和处理消息,然后把控制返还给Windows。
消息的分类队列消息和非队列消息从消息的发送途径上看,消息分两种:队列消息和非队列消息。
队列消息送到系统消息队列,然后到线程消息队列;非队列消息直接送给目的窗口过程。
这里,对消息队列阐述如下:Windows维护一个系统消息队列(System message queue),每个GUI线程有一个线程消息队列(Thread message queue)。
鼠标、键盘事件由鼠标或键盘驱动程序转换成输入消息并把消息放进系统消息队列,例如WM_MOUSEMOVE、WM_LBUTTONUP、WM_KEYDOWN、WM_CHAR等等。
Windows每次从系统消息队列移走一个消息,确定它是送给哪个窗口的和这个窗口是由哪个线程创建的,然后,把它放进窗口创建线程的线程消息队列。
线程消息队列接收送给该线程所创建窗口的消息。
线程从消息队列取出消息,通过Windows把它送给适当的窗口过程来处理。
除了键盘、鼠标消息以外,队列消息还有WM_PAINT、WM_TIMER和WM_QUIT。
这些队列消息以外的绝大多数消息是非队列消息。
系统消息和应用程序消息从消息的来源来看,可以分为:系统定义的消息和应用程序定义的消息。
系统消息ID的范围是从0到WM_USER-1,或0X80000到0XBFFFF;应用程序消息从WM_USER(0X0400)到0X7FFF,或0XC000到0XFFFF;WM_USER到0X7FFF 范围的消息由应用程序自己使用;0XC000到0XFFFF范围的消息用来和其他应用程序通信,为了ID的唯一性,使用::RegisterWindowMessage来得到该范围的消息ID。
但是在当前例子中,当前对象的类CTview没有覆盖该函数,所以CWnd的WindowProc被调用。
MFC 消息映射编程实验实验报告姓名:杨培培班级:电气12级3班12053307【预备知识】1、消息映射消息映射本质上就是一个数组,MFC 使用消息映射建立消息和类的成员函数的对应关系。
消息映射数组中存储的信息(1) 所处理的消息;(2) 消息应用的控件ID,或者ID 范围;(3) 消息所传递的参数;(4) 消息所期望的返回值。
2、消息映射宏下面介绍常用的两个消息映射宏:(1)ON_MESSAGE:处理任意消息语法规则:ON_MESSAGE(ID,func)LRESULT func(WPARAM wParam, LPARAM lParam);举例:映射鼠标左键按下消息ON_MESSAGE(WM_LBUTTONDOWN, OnLButtonDown)LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam);(2)ON_COMMAND:处理WM_COMMAND 消息语法规则:ON_COMMAND(ID,func)void func( );举例:映射菜单项命令消息ON_COMMAND(ID_OPER_TEST, OnOperTest)void OnOperTest ( );3、消息映射步骤MFC 中手工添加消息映射按照如下步骤进行:(1)在BEGIN_MESSAGE_MAP 和END_MESSAGE_MAP 之间添加消息映射宏;BEGIN_MESSAGE_MAP(CDemoView, CView)ON_MESSAGE(WM_KEYDOWN, OnKeyDown)ON_COMMAND(ID_OPER_TEST, OnOperTest)END_MESSAGE_MAP( )(2) 在类声明中声明成员函数;(3) 在类的实现部分实现成员函数。
【实验目的】(1) 熟悉Visual Studio 开发环境;(2) 掌握消息映射机制的基本原理和手工添加消息映射的方法;(3) 熟练掌握在Visual Studio 开发环境调试程序的方法。
【实验内容】设计 MFC 应用程序,手工添加消息映射,实现下面的功能:(1) 按下CTRL 键,拖动鼠标绘制矩形;(2) 按下SHIFT 键,拖动鼠标绘制椭圆。
【实验报告】(1) 总结手工添加消息映射的基本步骤;①在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间添加消息映射宏;BEGIN_MESSAGE_MAP(CDemoView, CView)ON_MESSAGE(WM_LBUTTONDOWN, OnLButtonDown)ON_COMMAND(ID_OPER_TEST, OnOperTest)END_MESSAGE_MAP( )②在类声明中声明成员函数;③在类的实现部分实现成员函数。
(2) 列出鼠标绘图功能的实现代码;源文件 Demo.cpp 代码#include "Demo.h"BEGIN_MESSAGE_MAP(CDemoWnd, CFrameWnd)ON_MESSAGE(WM_LBUTTONDOWN,OnLButtonDown)ON_MESSAGE(WM_MOUSEMOVE,OnMouseMove)ON_MESSAGE(WM_LBUTTONUP,OnLButtonUp)ON_MESSAGE(WM_TIMER,OnTimer)END_MESSAGE_MAP()LRESULT CDemoWnd::OnLButtonDown(WPARAM wParam, LPARAM lParam){m_X0 = m_X1 = LOWORD(lParam);m_Y0 = m_Y1 = HIWORD(lParam);return 0;}LRESULT CDemoWnd::OnMouseMove(WPARAM wParam, LPARAM lParam){/*CClientDCdc(this);dc.SelectStockObject(WHITE_PEN);if((wParam& MK_LBUTTON) && (wParam& MK_CONTROL)){dc.Ellipse(m_X0,m_Y0,m_X1,m_Y1);}if((wParam& MK_LBUTTON) && (wParam& MK_SHIFT)){dc.Rectangle(m_X0,m_Y0,m_X1,m_Y1);}m_X1 = LOWORD(lParam);m_Y1 = HIWORD(lParam);dc.SelectStockObject(BLACK_PEN);if((wParam& MK_LBUTTON) && (wParam& MK_CONTROL)){dc.Ellipse(m_X0,m_Y0,m_X1,m_Y1);}if((wParam& MK_LBUTTON) && (wParam& MK_SHIFT)){dc.Rectangle(m_X0,m_Y0,m_X1,m_Y1);}return 0; */CClientDC dc(this);CPen hp,*pOldPen,hp1;hp.CreatePen(PS_SOLID,3,RGB(255,0,0));pOldPen=dc.SelectObject(&hp);CPoint point [3];point [0] = CPoint(m_X0,(m_Y0+m_Y1)/2);point [1] = CPoint(m_X0,m_Y0);point [2] = CPoint((m_X0+m_X1)/2, m_Y0);if((wParam & MK_CONTROL) && (wParam & MK_LBUTTON)) //按下ctrl键,拖动鼠标绘制矩形{dc.Rectangle(m_X0,m_Y0,m_X1,m_Y1);}if((wParam & MK_SHIFT) && (wParam & MK_LBUTTON))//按下shift键,拖动鼠标绘制椭圆{dc.Rectangle(m_X0,m_Y0,(m_X0+m_X1)/2,(m_Y0+m_Y1)/2);hp1.CreatePen(PS_SOLID,3,RGB(255,255,255));pOldPen=dc.SelectObject(&hp1);dc.Polyline(point, 3);dc.SelectObject(pOldPen);dc.Ellipse(m_X0,m_Y0,m_X1,m_Y1);}m_X1= LOWORD(lParam);m_Y1 = HIWORD(lParam);return 0;}LRESULT CDemoWnd::OnLButtonUp(WPARAM wParam, LPARAM lParam){/* CClientDCdc(this);dc.SelectStockObject(WHITE_PEN);if((wParam& MK_LBUTTON) && (wParam& MK_CONTROL)){dc.Ellipse(m_X0,m_Y0,m_X1,m_Y1);}if((wParam& MK_LBUTTON) && (wParam& MK_SHIFT)){dc.Rectangle(m_X0,m_Y0,m_X1,m_Y1);}m_X1 = LOWORD(lParam);m_Y1 = HIWORD(lParam);dc.SelectStockObject(BLACK_PEN);if(wParam& MK_CONTROL){dc.Ellipse(m_X0,m_Y0,m_X1,m_Y1);}if(wParam& MK_SHIFT){dc.Rectangle(m_X0,m_Y0,m_X1,m_Y1);}return 0; */m_X0=m_X1= LOWORD(lParam);m_Y0=m_Y1= HIWORD(lParam);return 0;}LRESULT CDemoWnd::OnLButton(WPARAM wParam, LPARAM lParam) {return 0;}BOOL CDemoApp::InitInstance(){CDemoWnd *pFrame = new CDemoWnd();pFrame->Create(0,_T("鼠标绘图程序"));pFrame->ShowWindow(m_nCmdShow);this->m_pMainWnd = pFrame;return TRUE;}头文件 Demo.h 代码#include <afxwin.h>class CDemoWnd: public CFrameWnd{public:int m_X0;int m_Y0;int m_X1;int m_Y1;protected:LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam);LRESULT OnMouseMove(WPARAM wParam, LPARAM lParam);LRESULT OnLButtonUp(WPARAM wParam, LPARAM lParam);LRESULT OnLButton(WPARAM wParam, LPARAM lParam);DECLARE_MESSAGE_MAP()};class CDemoApp: public CWinApp{public:BOOL InitInstance();};CDemoApp ThisApp; // 全局应用程序对象【实验结果】(3) 总结实验的心得体会,实验中遇到的困难以及解决的方法等。
在上课时,老师的上机演示,让我对MFC消息映射有了初步的了解,也让我对编程产生了兴趣。
本次实验考查了MFC消息映射编程,我熟悉了Visual Studio的开发环境,同时也掌握了消息映射机制的基本原理和手工添加消息映射的方法。
在实验过程中也遇到了一些困难,通过询问同学,和查阅资料,让我对MFC编程也有了进一步的认知,同时也使我完成了本次实验。