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

  一,消息映射机制

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);

 

二,有关绘图
如何获得一个窗口类的句柄?

每一个从CWnd类继承的类都有一个数据成员m_hWnd保存了这个窗口的句柄。

注意区分窗口的句柄和指向窗口类的指针

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

要想画图就要有DC句柄,获得DC句柄的方式有很多,注意它们的区别。

1,使用SDK获取DC句柄GetDCReleaseDC要同时使用
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类的对象可以访问客户区和非客户区,即整个屏幕区域。

5GetParent()得到父窗口指针;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
)静态数据成员需要在类外单独做初始化,形式如: 变量类型 类名::变量名=初始值;

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值