GDI+概述及双缓冲绘图技术

1.GDI概述及实例分析

1.1 GDI概述

GDI在全称是Graphics Device Interface,即图形设备接口。是图形显示与实际物理设备之间的桥梁。GDI使得用户无需关心具体设备的细节,而只需在一个虚拟的环境(即逻辑设备)中进行操作。它的桥梁作用体现在:
(1)用户通过调用GDI函数将逻辑空间的操作转化为具体针对设备驱动程序的调用。
为实现图形设备无关性,Windows 的绘图操作在一个设备描述表上进行。用户拥有自己的"逻辑坐标"系统,它独立于实际的物理设备,与"设备坐标"相对应。开发Windows应用程序时,程序员关心的是逻辑坐标,我们在逻辑坐标系上绘图,利用GDI将逻辑窗口映射到物理设备上。
(2)GDI能检测具体设备的能力,并依据具体的设备以最优方式驱动这些设备,完成真实的显示。
GDI函数大致可分类为:
设备上下文函数(如GetDC、CreateDC、DeleteDC)
画线函数(如LineTo、Polyline、Arc)
填充画图函数(如Ellipse、FillRect、Pie)
画图属性函数(如SetBkColor、SetBkMode、SetTextColor)
文本、字体函数(如TextOut、GetFontData)
位图函数(如SetPixel、BitBlt、StretchBlt)
坐标函数(如DPtoLP、LPtoDP、ScreenToClient、ClientToScreen)
映射函数(如SetMapMode、SetWindowExtEx、SetViewportExtEx)
元文件函数(如PlayMetaFile、SetWinMetaFileBits)
区域函数(如FillRgn、FrameRgn、InvertRgn)
路径函数(如BeginPath、EndPath、StrokeAndFillPath)
裁剪函数(如SelectClipRgn、SelectClipPath)
GDI接口是基于函数,虽然使程序员省力不少,但是编程方式依然显得麻烦。例如显示一张位图,我们需要进行“创建位图,读取位图文件信息,启用场景设备,调色板变化“等一系列操作。然而有了GDI+,繁琐的步骤再次被简化。顾名思义,GDI+就是GDI的增强版,它是微软在Windows 2000以后操作系统中提供的新接口。

2.2 GDI绘制实例         

GDI在使用设备上下文绘制线条之前,必须先调用SelectObject 以使笔对象和设备上下文关联。其后,在设备上下文中绘制的所有线条均使用该笔,直到选择另一支不同的笔为止。
使用GDI画线代码如下:
CClientDC clientDC; //目标DC  
CPen pen (PS_SOLID, 1, RGB(0, 0, 255));  
clientDC.SelectObject(pen.GetSafeHandle()); //开始绘制  
clientDC.MoveTo(0, 0);  
clientDC.LineTo(rect.right, 0);  
clientDC.SelectObject(oldObject);  
从上述代码可以看出: 在GDI编程中,几乎所有的操作都围绕设备上下文dc展开。的确,这正是GDI编程的特点!设备上下文是 Windows 使用的一种结构,所有GDI操作前都需取得特定设备的上下文,函数中的CClientDC dc (this) 语句完成这一功能。 
利用GDI进行图形、图像处理的一般操作步骤为:
1. 取得指定窗口的DC。
2. 确定使用的坐标系及映射方式。
3. 进行图形、图像或文字处理。
4. 释放所使用的DC。
但是,在GDI+中,只需将Pen对象直接作为参数传递给Graphics类的DrawLine等方法即可,而不必使Pen对象与 Graphics对象关联。

2.GDI+概述及实例分析

2.1 GDI+概述

GDI+主要提供以下三种功能:         
(1) 二维矢量图形:GDI+提供了存储图形基元自身信息的类(或结构体)、存储图形基元绘制方式信息的类以及实际进行绘制的类;
(2) 图像处理:大多数图片都难以划定为直线和曲线的集合,无法使用二维矢量图形方式进行处理。因此,GDI+为我们提供了Bitmap、Image等类,它们可用于显示、操作和保存BMP、JPG、GIF等图像格式。
(3) 文字显示:GDI+支持使用各种字体、字号和样式来显示文本。         相比于GDI,GDI+是基于C++类的对象化的应用程序接口,因此用起来更为简单。GDI的核心是设备上下文,GDI函数都依赖于设备上下文句柄,其编程方式是基于句柄的;GDI+无需时刻依赖于句柄或设备上下文,用户只需创建一个Graphics 对象,就可以用面向对象的方式调用其成员函数进行图形操作,编程方式是基于对象的。

2.2 GDI+绘图实例

/CClientDC clientDC (this);  
//创建Graphics对象  
Graphics graphics(clientDC);  
//创建pen  
Pen myPen;  
myPen.SetWidth(1);  
//画X轴  
myPen.SetColor(Color::Blue);  
graphics.DrawLine(&myPen, 0, 0, rect.right, 0);  
(1)创建 Graphics 对象:Graphics 对象表示GDI+绘图表面,是用于创建图形图像的对象。
(2)使用 Graphics 对象绘制线条和形状、呈现文本或显示与操作图像。
GDI+的相对与GDI而言,新增了一系列功能:渐变的画刷(Gradient Brushes)、基数样条函数(Cardinal Splines)、持久的路径对象(Persistent Path Objects)、变形和矩阵对象(Transformations &Matrix Object)、可伸缩区域(Scalable Regions)、Alpha混合(Alpha Blending)和丰富的图像格式支持等。

3.双缓冲绘图技术:防闪烁

在图形图象处理编程过程中,双缓冲是一种基本的技术。我们知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。解决这一问题的有效方法就是双缓冲技术。
因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。于是我们就看到了闪烁现象。
我们会很自然的想到,避免背景色的填充是最直接的办法。但是那样的话,窗体上会变的一团糟。因为每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。所以单纯的禁止背景重绘是不够的。我们还要进行重新绘图,但要求速度很快,于是我们想到了使用BitBlt函数。它可以支持图形块的复制,速度很快。我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪烁。以上也就是双缓冲绘图的基本的思路。

3.1 普通方法进行频繁画图

按普通做图的方法进行编程。即在对话框的OnPaint函数中添加绘图代码。绘制若干同心圆,代码如下:
CDC* pDoc = mypic.GetDC();   
CPoint ptCenter;  
CRect rect,ellipseRect;  
GetClientRect(&rect);  
ptCenter = rect.CenterPoint();  
for(int i=20;i>0;i--)  
{  
    ellipseRect.SetRect(ptCenter,ptCenter);  
    ellipseRect.InflateRect(i*10,i*10);  
    pDC->Ellipse(ellipseRect);   
}  
运行的时候,我们会发现有闪烁现象。

3.2 双缓冲方法

在双缓冲方法中,首先要做的是屏蔽背景刷新。背景刷新其实是在响应WM_ERASEBKGND消息。我们在类中添加对这个消息的响应,可以看到缺省的代码如下:
BOOL CMYView::OnEraseBkgnd(CDC* pDC)  
{  
     return CView::OnEraseBkgnd(pDC);  
} 
是调用父类的OnEraseBkgnd函数,我们屏蔽此调用,只须直接return TRUE;即可。
 
介绍内存缓冲作图的步骤
CPoint ptCenter;  
CRect rect,ellipseRect;  
GetClientRect(&rect);  
ptCenter = rect.CenterPoint();  
CDC* pDC = mypic.GetDC();CDC dcMem; //用于缓冲作图的内存DC  
CBitmap bmp; //内存中承载临时图象的位图  
dcMem.CreateCompatibleDC(pDC); //依附窗口DC创建兼容内存DC  
bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());//创建兼容位图  
dcMem.SelectObject(&bmp); //将位图选择进内存DC  
//按原来背景填充客户区,不然会是黑色  
dcMem.FillSolidRect(rect,pDC->GetBkColor());  
for(int i=20;i>0;i--) //在内存DC上做同样的同心圆图象  
{  
    ellipseRect.SetRect(ptCenter,ptCenter);  
    ellipseRect.InflateRect(i*10,i*10);  
    dcMem.Ellipse(ellipseRect);  
}  
pDC->BitBlt(0,0,rect.Width(),rect.Height(),  
&dcMem,0,0,SRCCOPY);//将内存DC上的图象拷贝到前台  
ReleaseDC();dcMem.DeleteDC(); //删除DC  
bm.DeleteObject(); //删除位图  
由于复杂的画图操作转入后台,我们看到的是速度很快的复制操作,自然也就消除了闪烁现象。注意:

这里面CreateCompatibleBitmap第一个参数不能用dcMem,这样的话创建的是黑白位图。如果你要创建彩色位图,需要用pDC,它用来创建了内存DC. 详细请见下面的MSDN:
When a memory device context is created, it initially has a 1-by-1 monochrome bitmap selected into it. If this memory device context is used in CreateCompatibleBitmap, the bitmap that is created is a monochrome bitmap. To create a color bitmap, use the hDC that was used to create the memory device context, as shown in the following code:
HDC memDC = CreateCompatibleDC ( hDC );  
HBITMAP memBM = CreateCompatibleBitmap ( hDC, nWidth, nHeight );  
SelectObject ( memDC, memBM );

你可能感兴趣的:(Debug)