《VC++深入详解》读书笔记——4.MFC消息映射机制和绘图DC的获取

来源:互联网 发布:多线程编程技术详解 编辑:程序博客网 时间:2024/05/21 17:01

一 . 消息映射机制

1.Windows应用程序消息处理
  Windows程序维护有自己的消息队列,保存了队列消息(当然也有非队列消息,它们直接发给窗口),并用过消息循环对消息进行处理。消息循环首先通过GetMessage取得消息并从队列中移走,对于加速键会调用TranslateAccelerator函数,对其进行翻译和处理,如果处理成功就不在调用TranslateMessage。如果不是加速键,就进行消息的转换和派发,让目的窗口的窗口过程来处理消息。示例代码: 

 while (GetMessage(&msg, NULL, 0, 0))   {     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))     {        TranslateMessage(&msg);        DispatchMessage(&msg);     }   }  

2.MFC消息映射
MFC使用同一窗口过程,但MFC消息映射隐藏了消息处理的过程。使用Class Wizard添加一个消息响应函数之后,有两个方面内容被提供用来实现消息映射。

a.消息映射声明和实现
在类的定义(头文件)里,添加声明消息映射的宏DECLARE_MESSAGE_MAP,在类的实现(源文件)里,通过BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()实现消息映射。

b.消息响应函数的声明和实现
当通过ClassWizard添加消息响应函数时就会自动添加函数的声明和实现,代码如下:
声明:

//{{AFX_MSG  afx_msg void OnTimer(UINT nIDEvent);  afx_msg void OnPaint();  //}}AFX_MSG  DECLARE_MESSAGE_MAP()  

映射:

BEGIN_MESSAGE_MAP(CTestDialog, CDialog)  //{{AFX_MSG_MAP(CTestDialog)  ON_WM_TIMER()  ON_WM_PAINT()  //}}AFX_MSG_MAP  END_MESSAGE_MAP() 

实现:

void CTestDialog::OnPaint()   {  }  void CTestDialog::OnTimer(UINT nIDEvent)   {         CDialog::OnTimer(nIDEvent);  }  

通过以上几个消息映射的宏,就可以完成MFC的消息映射,关于MFC的消息映射机制,以下两篇文章做了很详细的论述:
MFC消息映射机制详解
MFC消息派发

3.消息响应的可能方式

a.在基类中针对每种消息做一个虚函数,当子类对消息响应时候,只要在子类中重写这个虚函数即可。缺点:MFC类派生层次很多,如果在基类对每个消息进行虚函数处理,那么从基类派生的每个子类都将背负一个庞大的虚表,这样浪费内存,故MFC没有采取这中方式而采取消息映射方式。

b.消息映射方式:MFC在后台维护了一个句柄和C++对象指针对照表,当收到一个消息后,通过消息结构里资源句柄(查对照表)就可找到与它对应的一个C++对象指针,然后把这个指针传给基类,基类调用WindowProc()函数对消息进行处理,WindowProc()函数中调用OnWndMsg()函数,真正的消息路由及处理是由OnWndMsg()函数完成的。由于WindowProc()和OnWndMsg()都是虚函数,而且是用派生类对象指针调用的,由多态性知最总终调用子类的。在OnWndMsg()函数处理的时候,根据消息种类去查找消息映射,判断所发的消息有没有响应函数,具体方式是先到相应的子类头文件两个AFX_MSG注释宏之间是否有相应的消息响应函数原型的声明;再到子类的源文件中,到BEGIN_MESSAGE_MAP和END_MESSAGE_MAP查找消息映射宏。当然,如果子类中没有对消息进行处理,则消息交由基类处理。

二.绘图DC的获取方式

1 . 使用SDK获取DC句柄(仅针对视类客户区)

HDC hdc;hdc=::GetDc(m_hWnd);//获取DC句柄MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);LineTo(hdc,point.x,point.y);::ReleaseDC(m_hWnd,hdc);//释放DC

2 . 利用MFC的CDC类指针和CWin类成员函数获取DC(仅针对视类客户区)

CDC *pDC=GetDC();pDC->MoveTo(m_ptOrigin);pDC->LineTo(point);ReleaseDC(pDC);

3 . 利用CClientDC对象(CClientDC类从CDC类派生来的,构造时调用GetDC(),析构时调用ReleaseDC(),仅针对视类客户区)

CClientDC dc(this);dc.MoveTo(m_ptOrigin);dc.LineTo(point);

如果获取父类窗口的一个设备句柄,可以调用:

CClientDC dc(GetParrent());

4 . 利用CWindowDC对象(CWindowDC类从CDC类派生来的,该对象可以访问整个窗口区域,包括客户区和非客户区)

CWindowDC dc(this);//dc.MoveTo(m_ptOrigin);dc.LineTo(point);

如果想在整个窗口画线:CWindowDC dc(GetParrent());
如果想在桌面画线:CWindowDC dc(GetDesktopWindow());

三.画笔画刷
利用画笔改变线条颜色和类型:

CPen pen(PS_DOT,1,RGB(0,255,0));//构造画笔对象CClientDC dc(this);CPen *pOldPen=dc.SelectObject(&pen);//将画笔选入DCdc.MoveTo(m_ptOrigin);dc.LineTo(point);dc.SelectObject(pOldPen);//恢复先前的画笔

使用画刷(通常利用画刷去填充矩形区域):

CBrush brush(RGB(255,0,0));//构造画刷对象CClientDC dc(this);dc.FillRect(CRect(m_ptOrigin,point),&brush);

使用位图画刷:

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

使用透明画刷:

CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//获取透明画刷对象指针CClientDC dc(this);CBrush *pOldBrush=dc.SelectObject(pBrush);//将透明画刷选入DCdc.Rectangle(CRect(m_ptOrigin,point));dc.SelectObject(pOldBrush);//释放透明画刷

在程序中,当构造一个GDI对象后,该对象并不会立即生效,必须选入设备描述表,它才会在以后的绘制操作中生效。一般情况下,在完成绘图操作之后,都要利用SelectObject函数把先前的GDI对象选入设备描述表,以便使其恢复到先前的状态。

0 0
原创粉丝点击