GDI+编程模块的变化
为了简化GDI+的编程开发过程,Microsoft对GDI+的编程模块作了一些调整,这主要体现在以下几个方面:
1、不再使用设备环境或句柄
我们知道,在使用GDI绘图时,必须要指定一个设备环境(DC)。MFC为设备环境提供了许多由基类CDC派生的设备环境类,如CPaintDC、CClientDC和CWindowDC等,用来将某个窗口或设备与设备环境类的句柄指针关联起来,所有的绘图操作都与该句柄有关。而GDI+不再使用这个设备环境或句柄,取而代之是使用Graphics对象。
与设备环境相类似,Graphics对象也是将屏幕的某一个窗口与之相关联,并包含绘图操作所需要的相关属性。但是,只有这个Graphics对象与设备环境句柄还存在着联系,其余的如Pen、Brush、Image和Font等对象均不再使用设备环境。
2、绘图方式的变化
先来看看同样绘制一条从点(20, 10)到点(200, 100)直线的GDI和GDI+代码,假设这些代码都是添加在OnDraw函数中。
GDI绘制该直线的代码如下:
void CMyView::OnDraw(CDC* pDC) { CMyDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); CPen newPen( PS_SOLID, 3, RGB(255, 0, 0) ); CPen* pOldPen = pDC->SelectObject( &newPen ); pDC->MoveTo( 20, 10 ); pDC->LineTo( 200, 100); pDC->SelectObject( pOldPen ); } |
GDI+绘制该直线的代码如下:
void CMyView::OnDraw(CDC* pDC) { CMyDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); using namespace Gdiplus; // 使用名称空间 Graphics graphics( pDC->m_hDC ); Pen newPen( Color( 255, 0, 0 ), 3 ); graphics.DrawLine(&newPen, 20, 10, 200, 100); } |
从上面代码可以看出,GDI先创建一个CPen(画笔)对象,然后通过SelectObject将该画笔选入到设备环境(pDC)中。接下来调用相应的画线函数,最后恢复设备环境中原来的GDI对象。而GDI+是先使用Graphics类创建一个与pDC设备环境相关联的Graphics对象,然后使用Pen类进行画笔的创建,最后调用相应的画线方法。由于Pen和设备环境是相互独立的,因而不需要像GDI那样恢复设备环境中原来的设置,而且Pen和Graphics对象的创建不存在先后次序。
2、Graphics绘图方法直接将Pen、Brush等对象作为自己的参数
从上面的代码可以看出,Graphics绘图方法直接将Pen对象作为自己的参数,从而避免了在GDI使用SelectObject进行繁琐的切换,类似的还有Brush、Path、Image和Font等。
3、不再使用"当前位置"
我们知道,GDI绘图操作(如画线)中总存在一个被称为"当前位置"的特殊位置。每次画线都是以此当前位置为起始点,画线操作结束之后,直线的结束点位置又成为了当前位置。设置当前位置的理由是为了提高画线操作的效率,因为在一些场合下,总是一条直线连着另一条直线,首尾相接。有了当前位置的自动更新,就可避免每次画线时都要给出两点的坐标。尽管有其必要性,但是单独绘制一条直线的场合总是比较多的,因此GDI+取消这个"当前位置"以避免当无法确定"当前位置"时所造成的绘图的差错,取而代之的是直接在DrawLine中指定直线起止点的坐标。
4、形状轮廓绘制和填充采用不同的方法
GDI总是让形状轮廓绘制和填充使用同一个绘图函数,例如Rectangle。我们知道,轮廓绘制需要一个画笔,而填充一个区域需要一个画刷。也就是说,不管我们是否需要填充所绘制的形状,我们都需要指定一个画刷,否则GDI采用默认的画刷进行填充。这种方式确实给我们带来了许多不便,现在GDI+将形状轮廓绘制和填充操作分开而采用不同的方法,例如DrawRectangle和FillRectangle分别用来绘制和填充一个矩形。
5、简化区域的创建
我们知道,GDI提供了许多区域创建函数,如CreateRectRgn、CreateEllpticRgn、CreateRoundRectRgn、CreatePolygonRgn和CreatePolyPolygonRgn等。诚然,这些函数给我们带来了许多方便。但在GDI+中,由于为了便于将区域引入矩阵变换操作,GDI+简化一般区域创建的方法,而将更复杂的区域创建交由Path接管。由于Path对象是与设备环境分离开来的,因而可以直接在Region构造函数中加以指定。