04 简单绘图_第三章简单绘图
04 简单绘图由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“第三章简单绘图”。
Leon 4
一、消息映射机制
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
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()相关联。这样一旦有消息的产生,就会自动调用相关联的消息响应函数去处理。
3)源文件中进行消息响应函数处理。(DrawView.cpp中自动生成OnLButtonDown函数轮廓,如下)
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your meage handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
}
说明:
可见当增加一个消息响应处理,在以上三处进行了修改。可在消息响应函数里添加消息处理代码完成对消息的响应、处理。
2.消息响应的方式:
MFC消息映射机制的实现方法:
在每个能接收和处理消息的类中,定义一个消息和消息函数对照表,即消息映射表。在消息映射表中,消息与对应的消息处理函数指针成对出现。某个类能处理的所有消息及其对应的消息处理函数的地址都列在这个类所对应的静态表中。当有消息需要处理时,程序只要搜索该消息静态表。查看表中是否含有该消息,就可知道该类能否处理此消息,如果能处理该消息,则同样依照静态表很容易找到并调用对应的消息处理函数。
MFC消息映射机制是针对能接受消息和处理消息的类来定义对应的消息映射表,而不是由父类来定义所有消息对应的虚函数,由子类来覆盖其函数实现,因为这样做会使程序背着一
个很大的虚拟函数表的包袱运行,对内存是一种浪费。
MFC消息映射机制的实现过程:
MFC在后台维护了一个窗口句柄和C++对象指针对照表,当收到一个消息后,通过消息结构中的窗口句柄(查对照表)就可找到与它对应的一个C++类对象指针,然后把这个指针传给基类,基类利用这个指针调用WindowProc()函数对消息进行处理,WindowProc()函数中调用OnWndMsg()函数,真正的消息路由及处理是由OnWndMsg()函数完成的。由于WindowProc()和OnWndMsg()都是虚函数,而且是用派生类对象指针调用的,由多态性知最总终调用子类的。在OnWndMsg()函数处理的时候,根据消息种类去查找消息映射,判断所发的消息有没有响应函数,具体方式是到相关的头文件和源文件中寻找消息响应函数声明(从注释宏//{{AFX_MSG(CDrawView)...//}}AFX_MSG之间寻找),消息映射(从宏BEGIN_MESSAGE_MAP(...)....END_MESSAGE_MAP()之间寻找),最终找到对应的消息处理函数。当然,如果子类中没有对消息进行处理,则消息交由基类处理。
二、有关绘图
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.利用CDC类指针和CWin类成员函数获取DC。(CDC:设备上下文对象的类)CDC *pDC=GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);
3.利用CClientDC对象。(从CDC类派生来的,对象只访问窗口的客户区)
CClientDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
4.利用CWindowDC对象。(从CDC类派生来的,对象可访问整个窗口区域)
CWindowDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
5.GetParent()得到父窗口指针;GetDesktopWindow()得到屏幕窗口指针。
CWindowDC dc(GetDesktopWindow());
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
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);//将旧的画笔选入DC
7.使用画刷(通常利用画刷去填充矩形区域):
使用单色画刷
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);//将透明画刷选入DC
dc.Rectangle(CRect(m_ptOrigin,point));
dc.SelectObject(pOldBrush);//将旧画刷选入DC,释放透明画刷 说明:
HGDIOBJ GetStockObject(int fnObject// type of stock object);
static CBrush* PASCAL FromHandle(HBRUSH hBrush);//FromHandle是一个静态方法,故可用CBrush::FromHandle()形式调用。
注意点:
1)静态方法不属于某一个具体对象,而属于类本身,在类加载的时候就已经为类静态方法分配了代码去,故可用CBrush::FromHandle()形式调用。
2)静态方法中,不能引用非静态的数据成员和方法。
3)静态数据成员需要在类外单独做初始化,形式如: 变量类型 类名::变量名=初始值;
8.绘制连续线条:
void CDrawView::OnMouseMove(UINT nFlags, CPoint point)
{
CClientDC dc(this);
CPen pen(PS_SOLID,1,RGB(255,0,0));
CPen *pOldPen=dc.SelectObject(&pen);//将画笔选入DC,并保存旧的画笔 if(m_bDraw==TRUE)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOrigin =point;//修改线段的起点
}
dc.SelectObject(pOldPen);//恢复DC
CView::OnMouseMove(nFlags, point);
}
绘制扇形效果的线条:
删除:m_ptOrigin =point;
绘制带边线的扇形:
红色处替换为
dc.LineTo(m_ptOld);
m_ptOld=point;
设置绘图模式的函数:SetROP2(R2_BLACK)。