当前位置:首页 > 资讯 > info6 > 正文

孙鑫VC++讲座笔记-(4)MFC消息映射机制的剖析

发表于: 2006-09-21   作者:cauthyxjs   来源:转载   浏览:
摘要: 一,消息映射机制1,消息响应函数:(例:在CDrawView类响应鼠标左键按下消息) 1)在头文件(DrawView.h)中声明消息响应函数原型。//{{AFX_MSG(CDrawView)  //注释宏afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);//}}AFX_MSG  //注释宏说明:在注释宏之间的声明在VC中灰色显示。afx_msg宏表示

一,消息映射机制

1,消息响应函数:(例:在CDrawView类响应鼠标左键按下消息)
 1)在头文件(DrawView.h)中声明消息响应函数原型。
//{{AFX_MSG(CDrawView)   //注释宏
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG   //注释宏
说明:

在注释宏之间的声明在VC中灰色显示。afx_msg宏表示声明的是一个消息响应函数。

 2)在源文件(DrawView.cpp)中进行消息映射。
BEGIN_MESSAGE_MAP(CDrawView, CView)
 //{{AFX_MSG_MAP(CDrawView)
 ON_WM_LBUTTONDOWN()//用户添加
 //}}AFX_MSG_MAP
 // Standard printing commands//系统自带
 ON_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()
说明:
在宏BEGIN_MESSAGE_MAP()与END_MESSAGE_MAP()之间进行消息映射。
宏ON_WM_LBUTTONDOWN()把消息WM_LBUTTONDOWN与它的响应函数OnLButtonDown()相关联。这样一旦有消息的产生,就会自动调用相关联的消息响应函数去处理。
宏ON_WM_LBUTTONDOWN()定义如下:
#define ON_WM_LBUTTONDOWN() /
 { WM_LBUTTONDOWN, 0, 0, 0, AfxSig_vwp, /
  (AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(UINT, CPoint))&OnLButtonDown },
 3)源文件中进行消息响应函数处理。(DrawView.cpp中自动生成OnLButtonDown函数轮廓,如下)
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 CView::OnLButtonDown(nFlags, point);
}
说明:
可见当增加一个消息响应处理,在以上三处进行了修改。可在消息响应函数里添加消息处理代码完成对消息的响应、处理。

2,消息响应的方式:
1)在基类中针对每种消息做一个虚函数,当子类对消息响应时候,只要在子类中重写这个虚函数即可。缺点:MFC类派生层次很多,如果在基类对每个消息进行虚函数处理,那么从基类派生的每个子类都将背负一个庞大的虚表,这样浪费内存,故MFC没有采取这中方式而采取消息映射方式。
2)消息映射方式:MFC在后台维护了一个句柄和C++对象指针对照表,当收到一个消息后,通过消息结构里资源句柄(查对照表)就可找到与它对应的一个C++对象指针,然后把这个指针传给基类,基类利用这个指针调用WindowProc()函数对消息进行处理,WindowProc()函数中调用OnWndMsg()函数,真正的消息路由及处理是由OnWndMsg()函数完成的。由于WindowProc()和OnWndMsg()都是虚函数,而且是用派生类对象指针调用的,由多态性知最总终调用子类的。在OnWndMsg()函数处理的时候,根据消息种类去查找消息映射,判断所发的消息有没有响应函数,具体方式是到相关的头文件和源文件中寻找消息响应函数声明(从注释宏//{{AFX_MSG(CDrawView)...//}}AFX_MSG之间寻找),消息映射(从宏BEGIN_MESSAGE_MAP(...)....END_MESSAGE_MAP()之间寻找),最终找到对应的消息处理函数。当然,如果子类中没有对消息进行处理,则消息交由基类处理。
说明:
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult);

 

二,有关绘图

由于框架类是视图类的父类,所以在框架类的有关显示有可能会被视图类覆盖。

1,使用SDK获取DC句柄:GetDC和ReleaseDC要同时使用
HDC hdc;
hdc=::GetDC(m_hWnd);//获取DC句柄,由于每个CWnd类派生的子类都继承了CWnd类的成员m_hWnd,即也就                                        //是CView类的句柄。
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);
LineTo(hdc,point.x,point.y);
::ReleaseDC(m_hWnd,hdc);//释放DC

2,利用CDC类指针和CWin类成员函数获取DC。
CDC *pDC=GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);

3,利用CClientDC对象。(CClientDC类从CDC类派生来的):
CClientDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);

说明:它在构造的时候调用GetDC,而在析构的时候自动调用ReleaseDC,它可以在客户区绘图,对于视图类而言,只有客户区,没有非客户区,而对于框架窗口来说,视图类的客户区就是它的客户区,非客户区包括标题栏和菜单栏。

4,利用CWindowDC对象。(CWindowDC类从CDC类派生来的)
CWindowDC dc(this);//
//CWindowDC dc(GetParent());//CDrawView的父类为框架类,即它可以在框架类的客户区上绘图包括工具栏等。
//CWindowDC dc(GetDesktopWindow());//得到屏幕窗口的指针,即可以访问所有屏幕区域。
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
说明:
CWindowDC类从CDC类派生来的,它在构造的时候调用窗口函数functionsGetWindowDC,而在析构的时候释放DC..CWindowDC类的对象可以访问客户区和非客户区,即整个屏幕区域。

5,GetParent()得到父窗口指针;GetDesktopWindow()得到屏幕窗口指针。

6,利用画笔改变线条颜色和类型:
CPen pen(PS_DOT,1,RGB(0,255,0));//构造画笔对象
CClientDC dc(this);CPen *pOldPen=dc.SelectObject(&pen);//将画笔选入DC,返回值为先前的画笔
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
dc.SelectObject(pOldPen);//恢复先前的画笔

7,使用画刷(通常利用画刷去填充矩形区域):
使用单色画刷
CBrush brush(RGB(255,0,0));//构造画刷对象
CClientDC dc(this);
dc.FillRect(CRect(m_ptOrigin,point),&brush);//用指定的画刷去填充矩形区域
说明:由于填充一个矩形区域FillRect中有一个参数指明所需要的画刷,所以就不需要选入设备描述表中了。

使用位图画刷
CBitmap bitmap;//构造位图对象(使用前需要初试化,即调用初始化函数)
bitmap.LoadBitmap(IDB_BITMAP1);//初试化位图对象,其余方法间MSDN
CBrush brush(&bitmap);//构造位图画刷
CClientDC dc(this);
dc.FillRect(CRect(m_ptOrigin,point),&brush);//用指定的位图画刷去填充矩形区域

使用透明画刷
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//获取透明画刷对象指针
CClientDC dc(this);//因为画Rectangle矩形的函数中没有提及画刷,所以要把画刷选入设备描述表中。
CBrush *pOldBrush=dc.SelectObject(pBrush);//将透明画刷选入DC
dc.Rectangle(CRect(m_ptOrigin,point));
dc.SelectObject(pOldBrush);//释放透明画刷
说明:
GetStockObject函数得到一个预先确定系统的画笔,画刷,字体,调色板等句柄。
HGDIOBJ GetStockObject(
  int fnObject   // type of stock object
);

FromHandle由一个窗口的HBRUSH对象的句柄转化为一个CBrush对象的指针。
static CBrush* PASCAL FromHandle( HBRUSH hBrush );//FromHandle是一个静态方法,故可用CBrush::FromHandle()形式调用。
注意点:
1)静态方法不属于某一个具体对象,而属于类本身,在类加载的时候就已经为类静态方法分配了代码去,故可用CBrush::FromHandle()形式调用。
2)静态方法中,不能引用非静态的数据成员和方法。
3)静态数据成员需要在类外单独做初始化,形式如: 变量类型 类名::变量名=初始值;

8,CDC::SetROP2方法:
int SetROP2( int nDrawMode );//设置当前绘图的模式

 

 

孙鑫VC++讲座笔记-(4)MFC消息映射机制的剖析

编辑推荐
对话框用户界面程序的编写,如何向对话框控件关联数据成员及其实现机理,如何利用对话框类的成员函
菜单的工作原理及编写应用,菜单命令消息在MFC框架程序的几个类中的传递顺序和处理过程。标记菜单、
MFC菜单命令更新机制---用该机制实现 Enable or Disable MenuItem 方法: 1)用资源中的菜单项"剪切"
18 1.容器和服务器程序 2.InvalidateControl重绘控件 3. 4.GetBackColor获取背景色 5.GetForeColor
一. 画线条的四种方法: 第一种 hdc=::GetDC(m_hWnd); MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NUL
1.CArchive类保存内存数据 2.CAchive类重载了>>与<<操作符,类似C++文件流 3.在OnNewDo
本机环境 IDE:VC6.0 OS:Win7 一,创建工程、设置环境、编写测试代码 创建工程: 新建一个Win32 Appl
1:windows OS事件驱动策略基于3种消息。标准消息、通告消息、命令消息。 2:“事件”就是“消息”
Windows应用程序是消息驱动的。在MFC 软件开发中,界面操作或者线程之间通信都会经常用到消息,通过
Win32程序消息流动 在讲MFC消息机制之前,先来介绍一下Win32程序的消息处理。 Win32程序的编写流程
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号