VC中GDI绘图上手必须了解清楚的几个概念

版权声明:本博客所有原创文章未经准许不得转载或保存转发,本人保留版权法律追诉权。 https://blog.csdn.net/haigear/article/details/85125873

如果我们使用过GDI+绘图,那么理解GDI绘图就很容易,不论在GDI还是GDI+中绘图,都需要一个绘图的“画板”,如果没有这个“画板”那么我们所绘制的图就没有地方承载,自然也就不能显示出来给人看见。
GDI+的绘图画板对象是一个Graphics对象,看起来,这个非常好理解,那是因为微软在开发.net这个时已经更多考虑它的易用性,自然也就将名称设置得要更易于理解。
GDI是MFC的绘图系统,GDI中的绘图“画板”是什么呢?
是DC(Device Context),意思是设备上下文,也有人称之为设备环境。不管怎么称呼,我们必须记住一点,没有DC(包括其子类)实例,我们的绘图则没有了“画板”,所以在我们绘图之前一定要创建或获得一个DC实例。

设备上下文(DC)
MFC中提供了几种典型的DC类,如CDC、CPaintDC、CClientDC、CWindowsDC及CMetaFileDC。
这里要特别注意到一个细节,这个细节对后面了解selectobject方法很有帮助,即DC在初始化的时候,系统会为其成员变量赋予默认的样式。

我们可以通过dc的相关方法获取当前的绘图工具的GDI成员变量样式(当然这些成员变量被隐藏了,我们不能直接访问),如:
在这里插入图片描述

其中,CDC类可以和其他的DC类进行数据交换,因为DC类的是其他DC的基类。所以我们可以在代码中看到,常常用来做兼容DC的都是CDC而不能使用其他的DC类。下面我们对最常用的CPaintDC和CClientDC分别讲解。

CPaintDC
CPiantDC类是OnPaint()函数使用的设备上下文类,它代表一个窗口的绘制画面,也就是说,这个时候整个窗口就是“画板”了。在基于对话框和视图的实例中都可以接收WM_PAINT的消息,凡是接受这个消息的对象也就有这个OnPaint方法。在类向导的消息与处理函数列表框中,我们可以都看到这样的类表:
在这里插入图片描述
当我们选择了WM_PAINT消息,那么MFC会自动为我们生成OnPaint的重写,如下:
在这里插入图片描述
可以看出来,一个CPaintDC的实例化和CDC的实例化一样,直接传入当前类的指针即可。
当用户改变了应用程序窗口的大小或者恢复了窗体先前被覆盖的部分,应用程序泽会受到Widnows消息队列中分派下来的WM_PAINT消息,那么窗体或者视图就会调用OnPaint方法。
在视图类(CView)中,OnPaint被调用的时候,OnPaint会调用OnDraw函数,因此编程的时候经常在OnDraw中输出图形。

CClientDC
CClientDC类是客户区的设备上下文,客户区就是指不包括边框、标题栏、菜单栏、工具栏、状态栏等界面元素的内部绘图区。当构造CClientDC类的对象时自动调用API函数GetDC()即可获得一个CClientDC的句柄,释放则用Release()方法。一般我们需要在鼠标或键盘事件或者自定义的方法进行图形绘制操作,那么CClientDC就是最好的选择,如:
在这里插入图片描述

这里,我们就在拖拽事件中用到了CClientDC。
CWindowsDC类,从名称上我们便可以猜到它代表整个应用程序窗口区域的设备上下文,包括边框、标题栏、菜单栏、工具栏、状态栏等。这里我们不详细讲了,因为我们用到他们的时候较少。
了解了CDC,我们就有了绘图的画板,那么我们还要有绘图的其他工具才行。接下来我们介绍绘图的其他及个必要方法,通过他们我们可以获得绘图时必要使用的必要工具和必要方法(CreateCompatibleDC和SelectObject)。

CDC的SelectObject方法
设备上下文初始化时,系统会自动赋予其默认的GDI绘图工具的样式,有默认的画笔、笔刷、字体样式,如果我们不通过selectObject将我们自己创建的GDI对象选中为当前绘图样式,那么MFC将仍然使用系统初始化时赋予DC的默认样式。
所以,我们可以知晓该方法的作用是将用户自己创建的GDI对象实例选择到DC中去。SelectObject有多种重载形式,可以选择用户已经定制好的画笔、笔刷、字体、位图等不同类型的GDI对象实例。如:
在这里插入图片描述
选择操作成功则返回该类型的指针(返回的上一次使用同类型的GDI对象),否则返回NULL。
有的绘制方法可以不需要事先调用selectobject

如:
如果你只是FillRect(hDC,&rc,hBrush);可以不用selectobject.
FillRect(hDC,&rc,hBrush);函数中有hBrush参数的意思是:你可以不使用当前device context中的brush(省得你自己再selectobject一次了).
比如,你把红刷子选进device context,你可以用绿刷子来FillRect.
DC的SelectStockObject方法
它与SelectObject不同的是,SelectObject所选择的对象必须先创建后选择,参数为一个GDI的指针,SelectStockObject不必要先创建GDI对象,而是可以直接使用系统预置的堆对象,也就是说它所接收的参数是一个系统定义的宏,如下:
在这里插入图片描述
我们可以看到,它接收的参数是一个整形值。

绘图工具(GDI对象)
通过绘图工具我们可以实例化GDI对象,如画笔、笔刷、字体等,但我们在使用绘图工工具的时候必须注意以下的严格四个步骤:
创建GDI
选择GDI(将对象选择进入DC中)
使用GDI
(使用完后)释放GDI
如以下代码示例:
在这里插入图片描述
CDC的CreateCompatibleDC方法
该函数创建一个与指定设备兼容的内存设备上下文环境(DC),大家可能对这句话不太理解。我们可以回忆一下前面的内容,我们说CDC类是其他DC类的基类,而且只有它可以跟其他DC进行数据交换,也就是说只有它才可以和其他DC类进行兼容。所以,也只有CDC才有这个方法,才能承担创建一个与指定“DC”类型相兼容的DC。
我们看一段这个方法的实例代码:

在这里插入图片描述
这段代码完成的工作就是将MemDC实例化成和dc兼容的DC了。
也许,我们又要问了,为什么要创建这个兼容上下文呢?直接将图形绘制到dc上不就完了吗?
实际上,直接绘制在CPaintDC或者CClientDC上肯定是可以的。
下面我们来具体了解一下这个函数:
函数原型:HDC CreateCompatibleDC(HDC hdc);
参数hdc:
表示现有设备上下文环境的句柄,如果该句柄为NULL,该函数创建一个与应用程序的当前显示器兼容的内存设备上下文环境。
返回值:
如果成功,则返回内存设备上下文环境的句柄;如果失败,则返回值为NULL。

CreateCompatibleDc函数只适用于支持光栅操作的设备,应用程序可以通过调用GetDeviceCaps函数来确定一个设备是否支持这些操作。
当不再需要内存设备上下文环境时,可调用DeleteDc函数删除它。
以下是一段MSN上的代码示例,我们可以通过它来了解这个函数的使用:
在这里插入图片描述
有许多老的VC程序依旧在使用GDI绘图,引入了.net框架支持的VC新版本也许可以考虑使用GDI+了,有关GDI+的绘图请参考我的C#中GDI+绘图轻松入门博文。

猜你喜欢

转载自blog.csdn.net/haigear/article/details/85125873