4MFC消息映射机制和CDC

http://blog.sina.com.cn/s/articlelist_1815328704_0_1.html


1.在单文档中view挡在MainFrame的前面。此时如果编写针对MainFrame的mouseClick事件,将不会有反应。
2.消息响应会在3处修改代码,1处是在头文件中,
//{{AFX_MSG(CDrawView)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()

另一处是cpp文件的begin MessageMap和End MessageMap之间,
BEGIN_MESSAGE_MAP(CDrawView, CView)
//{{AFX_MSG_MAP(CDrawView)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
//}}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()


//----------------------------------------------------------
最后是要有函数实现的代码。
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TOD Add your message handler code here and/or call default
m_ptOrigin=m_ptOld=point;
m_bDraw=TRUE;
CView::OnLButtonDown(nFlags, point);
}
3.画线:定义一个成员变量保存mouseDown的点m_Point
  1)API函数方法画线用HDC
  2)用CDC类成员函数画线。此时别忘记ReleaseDC
  3)用CClientDC
  4)用CWindowDC,用它甚至可以整个屏幕区域画线。

下面是上面4种方法的代码
需要在上面的OnLButtonDown函数的后面加:
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point){

HDC hdc;
hdc=::GetDC(m_hWnd);
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);
LineTo(hdc,point.x,point.y);
::ReleaseDC(m_hWnd,hdc);必须成对使用。

CDC *pDC=GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);必须成对使用。

//CClientDC dc(this);
CClientDC dc(GetParent());
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);//此处不需要ReleaseDC,因为CClientDC会自动释放DC

//CWindowDC dc(this);
//CWindowDC dc(GetParent());
CWindowDC dc(GetDesktopWindow());//此时可以在整个屏幕上画线。
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);

CPen pen(PS_DOT,1,RGB(0,255,0));
CClientDC dc(this);
CPen *pOldPen=dc.SelectObject(&pen);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
dc.SelectObject(pOldPen);

 
透明矩形:
CClientDC dc(this)
//CBRUSH::FromHandle是静态成员函数,所以可以用下面的方法调用。
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
CBrush *pOldBrush=dc.SelectObject(pBrush);
dc.Rectangle(CRect(m_ptOrigin,point));
dc.SelectObject(pOldBrush);
m_bDraw=FALSE;


//------------------------------------------------------
4.MFC中隐式的包含了windows.h。为什么?
因为在AFXV_W32.h文件中:
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
在AFXWIN.h中
// Note: WINDOWS.H already included from AFXV_W32.H

5.如何从句柄获得对象的指针?
FromHandle

6.类的静态成员函数可以由类名直接调用,也可以由对象调用。可以认为静态成员函数并不属于某个对象,它属于类 本身。程序运行伊始,即使没有实例化类的对象,静态成员函数和静态成员变量已然有其内存空间。静态成员函数不能访问非静态成员变量!静态成员变量必须在类 的外部初始化。当然如果并不打算用到静态成员变量,此时你可以不初始它。
7.理解代码区,数据区,堆,栈!
请见下面的简介:
http://www.downcode.com/server/j_server/J_1010.Html
对 于一个进程的内存空间而言,可以在逻辑上分成3个部份:代码区,静态数据区和动态数据区。动态数据区一般就是“堆栈”。“栈(stack)”和“堆 (heap)”是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”,所以每个线程虽然代码一样,但本地变量的 数据都是互不干扰。一个堆栈可以通过“基地址”和“栈顶”地址来描述。全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通 过堆栈的基地址和偏移量来访问本地变量。
 
MFC消息映射机制的剖析,讲述如何运用ClassWizard,,理解发送给窗口的消息是如何被MFC框架通过窗口句 柄映射表和消息映射表来用窗口类的函数进行响应的。掌握设备描述表及其封装类CDC的使用,CDC是如何与具体的设备发生关联的,融合具体的画图程序进行 分析。如何设置封闭图形的填充刷子(位图画刷与透明画刷的使用)。
一,消息映射机制
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
//.....
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使用虚函数发送消息,CWnd将 为超过100个消息来声明虚函数。对于在程序中使用的每一个派生类,C++都要求一个名为vtable虚函数分发表。不管这些函数是否确实在派生类中重 载,对于每一个虚函数,每一个vtable都需要一个4字节输入项。这样,对于窗口或者空间的每一个不同类型,应用程序将需要400多字节的表来支持虚拟 消息处理程序。MFC类派生层次很多,如果在基类对每个消息进行虚函数处理,那么从基类派生的每个子类都将背负一个庞大的虚表,这对资源是很大的浪费。
2) 消息映射方式:MFC在后台维护了一个句柄(例如窗口的句柄)和C++对象指针的对照表,当收到一个消息后,通过消息结构里资源句柄(查对照表)就可找到 与它对应的一个C++对象指针,然后把这个指针传给基类,基类利用这个指针调用WindowProc()函数对消息进行处理,WindowProc()函 数中调用OnWndMsg()函数,真正的消息路由及处理是由OnWndMsg()函数完成的。由于WindowProc()和OnWndMsg()都是 虚函数,而且是用派生类对象指针调用的,由多态性知最终调用子类的。在OnWndMsg()函数处理的时候,根据消息种类去查找消息映射,判断所发的消息 有没有响应函数,具体方式是到相关的头文件和源文件中寻找消息响应函数声明(从注释宏//{{AFX_MSG(CDrawView)... //}}AFX_MSG之间寻找),消息映射(从宏BEGIN_MESSAGE_MAP(...)....END_MESSAGE_MAP()之间寻 找),最终找到对应的消息处理函数。当然,如果子类中没有对消息进行处理,则消息交由基类处理。




二,一些基本绘图函数
1,关于CPoint(摘自Visual C++技术内幕第五版)。
CRect、CPoint和CSize类是由Windows RECT、POINT和SIZE结构派生出来的,因此,他们继承了公用整数型数据成员,如下所示:
 CRect 左、上、右、下
 CPoint x、y
 CSize cx、cy
如果查看《Microsoft Foundation Class Reference》,你将看到,这三个类有大量的重载运算符。你可以在其他程序中完成如下操作:
添加CSize对象到一个CPoint对象。
从CPoint对象中减去一个CSize对象。
从CPoint对象中减去另一个CPoint,产生一个CSize对象。
把CPoint或者CSize对象添加到CRect对象。
从CRect对象中减去CPoint或者CSize对象。
CRect 类有与CSize和CPoint相关的成员函数。例如,TopLeft成员函数返回一个CPoint对象,并且,Size成员函数返回一个CSize对 象。从这一点可以看出,CSize对象是“两个CPoint对象的差”,并且,可以通过CPoint对象的差来获得CRect对象。

6,GetParent()得到父窗口指针,GetDesktopWindow()得到桌面窗口指针。


7.The GetStockObject function retrieves a handle to one of the predefined stock pens, brushes, fonts, or palettes.
HGDIOBJ GetStockObject(
  int fnObject   // type of stock object
);
Returns a pointer to a CBrush object when given a handle to a Windows HBRUSH object.

static CBrush* PASCAL FromHandle( HBRUSH hBrush );//FromHandle是一个静态方法
10,CDC::SetROP2方法:
int SetROP2( int nDrawMode );
设置当前的绘图模式。绘图模式指定了如何把画笔和填充物的内部颜色与显示表面已存在的颜色进行组合。
绘图模式仅用于光栅装置;它不用于向量装置。绘图模式是二进制的光栅操作代码,使用二元操作符AND,OR和XOR,以及一元操作符NOT,表达了两个变量所有可能的布尔组合。


virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
//位置:WINCORE.CPP Ln1592
LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
 // OnWndMsg does most of the work, except for DefWindowProc call
 LRESULT lResult = 0;
 if (!OnWndMsg(message, wParam, lParam, &lResult))
  lResult = DefWindowProc(message, wParam, lParam);
 return lResult;
}
virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值