GDI+学习之路2--新特性

 

Microsoft Windows GDI+ 不同于GDI体现在2个方面。第一,GDI+通过提供新的功能扩展了GDI的特性,比如渐变画刷和半透明混合。第二,编程模型的改进使得图形开发更加简单和灵活。

相对于GDI的新特性

渐变画刷(Gradient Brushes

         GDI+通过提供用于填充图形、路径、区域的线性渐变和路径渐变画刷来扩展了GDI的功能。渐变画刷同样能够被用来绘制线条、曲线、路径。当您采用线性渐变画刷填充图形的时候,颜色将在穿越该图形时逐渐改变,例如,假设您创建了一个水平渐变画刷,同时指定左边缘为蓝色、右边缘为绿色。当您采用水平渐变画刷填充图形时,颜色将从它的左边到右边逐渐由蓝色过渡到绿色。同样地,一个垂直渐变画刷填充的图形的颜色将自上而下渐变。下面两幅插图显示了一个水平渐变画刷填充的椭圆和一个对角渐变画刷填充的区域。

如果您采用路径渐变画刷填充图形,您可以有许多选择来指定颜色从图形的一个区域到另一个区域如何过渡。一种选择就是设置一个中心颜色和边界颜色,这样图形由内向外象素颜色将逐渐改变。下图显示的是一个由路径渐变画刷填充的路径(由一对贝塞尔样条所创建)。

基数样条(Cardinal Splines

GDI+支持基数样条,而GDI不支持。基数样条是一组单个曲线按照一定的顺序连接而成的一条较大曲线。样条由一系列点指定,并通过每一个指定的点。由于基数样条平滑地穿过组中的每一个点(不出现尖角),因而它比用直线连接创建的路径更精确。下面是分别使用两种方法创建的图形,一个使用基数样条,一个使用直线。

独立的路径对象(Independent Path Objects

         GDI中,一条路径是属于一个设备场景的,在绘制完成后就被销毁了。在GDI+中,绘图工作由Graphics对象来完成,您可以创建和保留几个与Graphics独立的GraphicsPath对象。绘图操作时GraphicsPath对象不被破坏,这样您就可以多次使用同一个GraphicsPath对象画路径了。

变换和矩阵对象(Transformations and the Matrix Object

GDI+提供了矩阵对象,一个非常强大的工具,使得图形变换(旋转、平移等)变得简单灵活。一个矩阵对象总是和一个被变换的图形对象相联系起来。比方说,GraphicsPath对象有一个Transform方法,它的一个参数能够接受Matrix对象的地址。单个3×3矩阵可以存储一个变换或者一系列变换。下图是一个路径变换前后的例子(先缩放后旋转)。

可伸缩区域(Scalable Regions

    GDI+在对区域的支持上对GDI进行了很大的改进。在GDI中,区域存储在设备坐标中,唯一可进行的区域变换的操作是平移。而GDI+用世界坐标存储区域,允许对区域进行任何图形变换(例如缩放),这种变换存储在一个变换矩阵中。下图显示的是经过连续3个变换前后的一个区域:缩放、旋转、平移

Alpha混合(Alpha Blending

    请注意上图中,您可以通过变换后的区域(阴影填充)看到变换前的区域(红色填充)。这种效果可以通过GDI+支持的α混合来实现。利用α混合,您可以指定填充颜色的透明度。透明色将与背景色混合填充色越透明,背景色显示越清晰。下图所示的四个椭圆被填充了同样的颜色(红色),但由于拥有不同的透明度而呈现不同的显示效果。

多种图像格式支持(Support for Multiple Image

         GDI+提供了ImageBitmapMetafile类,用于载入、保存和处理多种格式的图形。以下格式均支持:BMPGraphics Interchange format(GIF)JPEGExifPNGTIFFICONWMFEWF

编程模式的变化

设备场景(Device Context)、句柄(Handles)和Graphics对象

如果您曾经使用过GDI编写过应用程序,您肯定对设备场景(DC)的概念非常熟悉。设备场景是Windows使用的一个数据结构,用于存储具体设备性能和与如何在设备上绘制项目的相关信息。而且视频显示器的设备场景还与显示器上的特定窗口有关。首先您必须获得一个设备场景句柄(HDC),然后在图形绘制时您把这个句柄作为一个参数传递给GDI函数。当然您也可以把它传递给获得或设置设备场景有关属性的函数。

您在使用GDI+的时候,您不必像在GDI中那样关心设备场景句柄。您只需简单地创建一个Graphics对象,然后以您熟悉的面向对象的方式(比如myGraphicsObject.DrawLine(parameters))调用它的方法即可。Graphics对象是GDI+的核心,正如设备场景是GDI的核心一样。设备场景(DC)和图形对象(Graphics)在不同的环境下扮演着同样的角色,发挥着类似的作用,但是两者也存在着本质的不同。前者使用基于句柄的编程模型而后者使用面向对象的编程模型。

Graphics对象和设备场景一样,与屏幕上的特定窗体有关,它包含着图形绘制的有关属性信息(比如,平滑模式和隐式文本渲染)。然而,Graphics对象并没有像GDI那样与PenPathImage或者Font等搅在一起。比如,在GDI中,您必须先调用SelectObject将一个Pen对象与设备场景关联,然后您才能使用设备场景绘制一条线。这被称为将画笔选入设备场景。您在设备场景中绘制的所有线条都将采用这个画笔直到您选择另一个画笔为止。在GDI+中,您只需将一个Pen对象作为参数传递给Graphics类的DrawLine方法即可。您可以在一连串的DrawLine调用中传入不同的Pen对象,而不必将给定的Pen对象与Graphics对象关联。

画线的两种方法(Two Ways to Draw a Line

GDI画线

HDC hdc;

PAINTSTRUCT ps;

HPEN hPen;

HPEN hPenOld;

hdc = BeginPaint(hWnd, &ps);

hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));

hPenOld = (HPEN)SelectObject(hdc, hPen);

MoveToEx(hdc, 20, 10, NULL);

LineTo(hdc, 200, 100);

SelectObject(hdc, hPenOld);

DeleteObject(hdc);

EndPaint(hWnd, &ps);

采用GDI画线,您需要2个对象:设备场景和画笔。您通过调用CreatePen获取一个句柄。紧接着,您调用SelectObject将画笔选入设备场景。然后调用MoveToEx将画笔位置设为(20,10),然后调用绘制一条直线到位置(200,100)。注意MoveToExLineTo均需要一个hdc作为参数。

GDI+C++类接口画线

HDC hdc;

PAINTSTRUCT ps;

Pen* myPen;

Graphics* myGraphics;

hdc = BeginPaint(hWnd, &ps);

myPen = new Pen(Color(255, 255, 0, 0), 3);

myGraphics = new Graphics(hdc);

myGraphics->DrawLine(myPen, 20, 10, 200, 100);

delete myGraphics;

delete myPen;

EndPaint(hWnd, &ps);

通过GDI+C++类接口画线,您需要一个Graphics对象和一个Pen对象。注意您不需要向这些对象提供窗体句柄。相反,您只需要构造一个Graphics类(一个Graphics对象)和一个Pen类(一个Pen对象)即可。画线涉及Graphics类的Graphics::DrawLine方法。Graphics::DrawLine方法的第一个参数是一个Pen对象的指针。较之前面将Pen选入设备场景的GDI例子,这种方案更加更加简单灵活。

不再有当前位置(No More Current Position

         注意,前面显示的DrawLine方法同时提供了线段的起点和终点作为参数。不同的是,在GDI中您必须先设置当前位置然后才能绘制一个起于(x1, y1)终于(x2, y2)的线段。GDI+中已经完全摒弃了当前位置的概念。

绘图与填充方法分离(Separate Methods for Draw and Fill

在绘制图形比如矩形的边框和填充其内部区域方面,GDI+GDI更加灵活。GDI有个Rectangle函数可以一步实现绘制矩形边框和填充其内部区域。边框采用当前选入的画笔绘制,内部区域采用当前选入的笔刷填充。

hBrush = CreateHatchBrush(HS_CROSS, RGB(0, 0, 255));

hPen = CreatePen(HS_SOLID, 3, RGB(255, 0, 0));

SelectObject(hdc, hBrush);

SelectObject(hdc, hPen);

Rectangle(hdc, 100, 50, 200, 80);

 

GDI+中,绘制矩形边框和填充其内部区域的方法是独立开来的。Graphics 类的DrawRectangle方法有一个参数,用于传入Pen对象的地址。而FillRectangle方法有一个参数,用于传入Brush对象的地址。

HatchBrush* myHatchBrush = new HatchBrush(

    HatchStyleCross,

    Color(255, 0, 255, 0);

    Color(255, 0, 0, 255));

Pen* myPen = new Pen(Color(255, 255, 0, 0), 3);

myGraphics.FillRectangle(myHatchBrush, 100, 50, 100, 30);

myGraphics.DrawRectangle(myPen, 100, 50, 100, 30);

注意,GDI+FillRectangleDrawRectangle方法的参数指定矩形的左、上、宽度和高度。相对地,在GDIRectangle函数中,参数指定的是矩形的左、右、上、下。同时还要注意,GDI+中的Color类的构造函数有4个参数。后面的3个参数就是通常的红、绿、蓝的值;第一个参数指定的是alpha半透明值,它表示该颜色与背景色混合的程度。

构造区域(Constructing Regions

GDI提供了几个函数可以创建区域:CreateRectRgnCreateEllpticRgnCreateRoundRectRgnCreatePolygonRgnCreatePolyPolygonRgn。您可能也期望GDI+中的Region类提供类似的构造函数,传入矩形、椭圆、圆角矩形和多边形作为参数,但是情况并非如此。在GDI+中,Region类提供一个传入Rect对象引用的构造函数,和另一个传入GraphicsPath对象地址的构造函数。如果您想创建一个基于椭圆、圆角矩形或者多边形的区域,您可以很容易地通过创建一个GraphicsPath对象(包含椭圆等),然后将GraphicsPath对象的地址传递给Region构造函数即可。

GDI+中可以很简单地通过图形和路径的组合创建一个复杂的区域。Region类有UnionIntersect方法,用于加入一个路径或者另一个区域到一个已有区域中。GDI+中一个很好的特性是,当一个GraphicsPath对象作为Region构造函数的参数传入的时候,它本身并不会被销毁。而在GDI中,您可以通过PathToRegion函数将一个路径转换为一个区域,但是同时路径也被销毁了。同样地,GraphicsPath对象在其地址作为Union(合并)和Intersect(相交)方法的参数传入时本身也不会被销毁,因此您可以将一个指定的路径作为一个组成部分来创建几个独立的区域。下面例子中,假设onePath一个GraphicsPath对象(简单抑或复杂)的指针并且已经被初始化:

Region region1(rect1);

Region region2(rect2);

Region1.Union(onePath);

Region2.Intersect(onePath);

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值