《VC++深入详解》第四章 简单绘图

来源:互联网 发布:高中生心理健康数据 编辑:程序博客网 时间:2024/04/29 19:28

这一章延续上对MFC框架的介绍,以一个画图例子程序讲解如下知识点:

1、ClassWizard的使用

2、MFC消息响应机制

3、设备描述表DC的一些封装以及常见绘图API


在本章例子中,我们先后尝试在框架窗口和视类窗口中响应鼠标左键按下消息,实际发现仅后者中能予以响应,这是因为视类窗口始终覆盖在框架窗口之上。

为一个窗口增加消息响应可以通过MFC Wizard来,也可以自行添加代码,主要修改有两个方面:

1、消息响应函数的声明和定义

2、将消息映射加入消息映射表,其实就是通过宏(ON_COMMAND、ON_WM_LBUTTONDOWN等)来完成。消息映射表是类的静态成员,它存放该类对于消息的响应情况。MFC在类的定义中使用宏DECLARE_MESSAGE_MAP来定义该static成员,只是宏的方式让这一切变得神秘起来。

#define DECLARE_MESSAGE_MAP() \private: \           static const AFX_MSGMAP_ENTRY _messageEntries[]; \
protected: \
<span style="white-space:pre"></span>   static AFX_DATA const AFX_MSGMAP messageMap;

下面引用一个来自《深入浅出MFC》中的插图,更易说明情况。


这里我们先来看看MFC里消息的分类,然后看看各类消息的路由区别。

1、命令消息WM_COMMAND 来自菜单、快捷键、工具栏按钮的消息。它们均以WM_COMMAND的方式呈现,那我们如何区分呢?在SDK程序里,主要依靠WParam参数,在MFC里依靠识别码来区分。

2、除了WM_COMMAND外其他的WM开头的消息都称为标准消息

3、Notification控件通知消息,为的是通知控件的父窗口。

对于标准消息,它的路由很简单,即从子类到父类。比如若CMyView未响应某个标准消息,则交由CView响应,后者若未响应则交给CWnd。

对于命令消息,它的路由情况复杂一些,依旧引用《深入浅出MFC》中的例图(经典书籍,本人水平太次,粗读一遍仍未领会贯通)


框架窗口在收到命令消息WM_COMMAND后,先给自己的View视类窗口一个机会,视类窗口若处理了该消息,则消息路由结束,如上图线路1所示。若未处理,则交给Document文档类处理,后者若未处理,则框架窗口就自己尝试处理,不成的话交给应用程序类(只要集成于CCmdTarget都可以处理命令消息),都不成的话交由DefWindowProc走默认的处理流程。

对于控件通知消息,一般都由父类窗口予以响应。


第一章中,我们使用HDC句柄实现了图形的绘制,当时调用的方式是

HDC hdc = GetDc(hWnd)

TextOut(hdc, 0, 0, "XXX", strlen("XXX"))

ReleaseDc(hWnd, hdc)

本章我们学习了几个更上层的封装DC类,比如CClientDC CWindowDC, 前者对HDC进行简单封装将GetDc 和 ReleaseDc放入构造与析构之中。

后者功能更强大,可以在非客户区甚至桌面进行绘图,只要给予其相应的窗口句柄即可。这里学习一个API:GetDesktopWindow

void CDrawView::OnLButtonUp(UINT nFlags, CPoint point) {//<span style="white-space:pre"></span>CClientDC dc(this);//CClientDC dc(GetParent());CWindowDC dc(GetDesktopWindow());//CWindowDC dc(GetParent());dc.MoveTo(m_ptOrigin);dc.LineTo(point);
}


上面的绘图都是使用默认的线条颜色、画刷,接下来,看看如何使用自定义的

通过DC句柄的成员函数SelectObject可以把GDI对象选入设备描述表中,实现对默认对象的更改,注意的是在绘图完成后,我们一般将更改之前的设备描述表予以恢复,不能只图自己方便。

红笔:

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

画刷:

有的GDI绘图函数提供了画刷接口,不需要我们选入设备描述表,比如:

CBrush brush(RGB(255,0,0));//创建并获得设备描述表CClientDC dc(this);//利用红色画刷填充鼠标拖曳过程中形成的矩形区域dc.FillRect(CRect(m_ptOrigin,point),&brush);
有的则没有提供接口,我们只能通过选入的方式来得到自己想要的设备特性,比如:

//创建并获得设备描述表CClientDC dc(this);//创建一个空画刷CBrush *pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//将空画刷选入设备描述表CBrush *pOldBrush = dc.SelectObject(pBrush);//绘制一个矩形dc.Rectangle(CRect(m_ptOrigin,point));//恢复先前的画刷dc.SelectObject(pOldBrush);

注意到上面的API:GetStockObject,在第一章设计窗口类时,曾经使用它获得一个黑色的画刷句柄。这里NULL_BRUSH将是一个透明的画刷句柄。

由于SelectObject需要的是画刷指针,我们使用FromHandle来从句柄获得指针。

通过本章的学习,进一步加深了MFC消息机制的理解,基本绘图方法的掌握。




0 0