windows编程技术14GDI+编程基础.docx

上传人:b****5 文档编号:6217424 上传时间:2023-01-04 格式:DOCX 页数:76 大小:1.55MB
下载 相关 举报
windows编程技术14GDI+编程基础.docx_第1页
第1页 / 共76页
windows编程技术14GDI+编程基础.docx_第2页
第2页 / 共76页
windows编程技术14GDI+编程基础.docx_第3页
第3页 / 共76页
windows编程技术14GDI+编程基础.docx_第4页
第4页 / 共76页
windows编程技术14GDI+编程基础.docx_第5页
第5页 / 共76页
点击查看更多>>
下载资源
资源描述

windows编程技术14GDI+编程基础.docx

《windows编程技术14GDI+编程基础.docx》由会员分享,可在线阅读,更多相关《windows编程技术14GDI+编程基础.docx(76页珍藏版)》请在冰豆网上搜索。

windows编程技术14GDI+编程基础.docx

windows编程技术14GDI+编程基础

第14章GDI+编程基础

GDI+(GraphicsDeviceInterfacePlus,图形设备接口加)是WindowsXP及以上版本操作系统的图形子系统,也是传统.NET框架的重要组成部分和窗体绘图的主要工具,负责在屏幕和打印机上绘制图形图像和显示信息。

顾名思义,GDI+是Windows早期版本所提供的图形设备接口GDI的后续版本,是建立在GDI之上的一个高层图形子系统。

GDI+是一种API,分别通过一套C++类和一套部署为托管代码的类来展现,这两套类分别被称为GDI+的“C++封装”和“托管类接口”。

GDI+不但在功能上比GDI要强大很多,而且在代码编写方面也更简单,因此会成为Windows图形图像程序开发的主要工具之一。

由于篇幅所限,本书只简单介绍利用MFC进行GDI+编程的一些基本内容,也不讲GDI+的API编程。

基于GDI+托管封装的.NET窗体绘图,将在第18章中再介绍。

对GDI+编程有兴趣的读者,可以参考如下图书:

●周鸣杨、赵景亮.精通GDI+编程.清华大学出版社,2004年2月(C++/MFC)。

●MaheshChand(韩江等译).GDI+图形程序设计.电子工业出版社,2005年3月(C#/.NET)。

本章将介绍GDI+的结构和组成,讨论GDI+的几个主要新增特性与功能,说明GDI+给Windows图形图像程序的开发模式带来的变化。

介绍C++封装的GDI+API的具体使用方法,主要讲解二维矢量图形绘制和文字显示等基本内容。

GDI+的路径、区域、变换、图像处理和图元文件等高级编程内容,安排在下一章介绍。

14.1GDI+的结构与组成

本节先介绍GDI+的体系结构,再列出C++封装的GDI+API的具体组成。

14.1.1GDI+的结构

GDI+是建立在GDI之上的一种高层图形子系统,基础是GDI+平面API,有C++和托管两种封装。

注意,虽然GDI+是GDI的发展,但是GDI+并非设计来替代GDI的,它不能独立工作,底层还得靠GDI实现。

1.GDI+的体系结构

GDI+与GDI一样,都具有设备无关性。

而且GDI+是建立在GDI之上的一种高层接口,供WindowsAPI和.NET框架调用。

与GDI类似,GDI+主要提供了二维矢量图形、图像处理和文字显示版式三类功能(参见图14-1),只是GDI+比GDI的功能更强大,且编程模式发生了改变。

图14-1GDI+的体系结构

2.GDI+平面API与封装

GDI+提供(expose)了一个平面(flat)API,它包含大约600个函数,被实现在Gdiplus.dll中,声明在Gdiplusflat.h内。

这些函数被包装到了前面讨论过的GDI+API的54个C++类的集合之中。

作为C++封装的替代方案,微软.NET框架提供了GDI+的一个托管代码封装类集,包含大约60个类、50个枚举和8个结构。

它们分属于下列命名空间:

System.Drawing、System.Drawing.Drawing2D、System.Drawing.Imaging、System.Drawing.Text和System.Drawing.Printing。

GDI+的平面API与其C++及托管封装的关系如图14-2所示。

图14-2GDI+的封装与使用

14.1.2GDI+的组成

GDI+的C++封装,包含了54个类、12个全局函数、(6类)226个图像常量、55种枚举和19种结构。

GDI+的.NET托管封装,则包含了大约60个类、50个枚举和8个结构。

这两种封装都是基于GDI+平面API的。

本小节只介绍GDI+的C++封装,GDI+的托管封装将在第18章的.NET窗体绘图中有所涉及。

1.类

GDI+的C++封装中共有54个类,核心类是Graphics,它是实际绘制直线、曲线、图形、图像和文本的类。

许多其它GDI+类是与Graphics类一起使用的。

例如,DrawLine方法接收Pen对象,该对象中存有所要绘制的线条的属性(颜色、宽度、虚线线型等)。

FillRectangle方法可以接收指向LinearGradientBrush对象的指针,该对象与Graphics对象配合工作来用一种渐变色填充矩形。

Font和StringFormat对象影响Graphics对象绘制文本的方式。

Matrix对象存储并操作Graphics对象的仿射变换——旋转、缩放和翻转图像。

GDI+还提供了用于组织图形数据的几种结构类(例如Rect、Point和Size)。

而且,某些类的主要作用是结构化数据类型。

例如,BitmapData类是Bitmap类的帮助器,PathData类是GraphicsPath类的帮助器。

图14-3是GDI+API类的层次结构图。

注意:

在GDI+、.NET、C#、Java和VB中,都把类的成员函数称为方法。

当我们在C++中,使用GDI+和.NET框架类库中的类和功能时,也常常将其函数改称为方法。

图14-3GDI+类的层次结构

2.全局函数

GDI+命名空间中的全局函数有12个,常用的有如下两个(其余的大多数与图像相关):

●关闭GDI+:

GdiplusShutdown(清除GDI+所使用的资源)。

●启动GDI+:

GdiplusStartup(初始化GDI+)。

3.常量、枚举和结构

GDI+中有6类共计226个图像常量(都被定义在头文件GdiplusImaging.h中),包括图像文件格式常量11个(如ImageFormatBMP、ImageFormatGIF、ImageFormatJPEG、ImageFormatPNG、ImageFormatTIFF等)、图像帧维常量2个、图像编码器常量13个、图像像素格式常量14个、图像特性标志类型9个、图像特性标志217个。

GDI+定义了55种枚举类型,它们都是相关常数的集合。

例如:

PenType、BrushType、DashStyle、ImageType、LineCap、FillMode、ImageFlags等。

GDI+API中还定义了19种结构,用于GDI+的各种方法调用中。

例如:

ColorMap、ColorMatrix、ColorPalette、GdiplusAbort、GdiplusStartupInput、GdiplusStartupOutput等。

14.2GDI+的特色

本节介绍GDI+的几个主要新增特性与功能,说明GDI+在编程模式上的改变。

14.2.1GDI+新增特性

与GDI相比,GDI+新增的特性主要有渐变画刷、样条和贝塞尔曲线、持久路径、矩阵变换、伸缩区域、α混色和对多种图像格式的支持。

1.渐变画刷

GDI+中新增加的渐变画刷(gradientbrush,梯度刷),通过提供用于填充图形、路径和区域的颜色线性渐变和路径渐变的画刷,扩展了GDI的功能。

渐变画刷可用于绘制直线、曲线和路径,参见图14-4。

a)(水平)线性渐变b)(贝塞尔)路径渐变

图14-4渐变画刷图14-5基样条曲线与折线

2.曲线方法

GDI+支持基样条(cardinalsplines)和贝塞尔(Bezier)方法,可以由若干控制点生成光滑的曲线,参见图14-5。

3.持久路径对象

GDI中的路径(path)属于设备上下文,并且会在绘制时被毁坏。

而GDI+则可以创建并维护多个与Graphics对象分开的持久(persistent)路径对象——GraphicsPath对象,在绘图操作时也不会破坏,因此可多次使用同一个GraphicsPath对象来绘制路径。

4.变换和矩阵对象

GDI+提供了Matrix(矩阵)对象,它是一种可以使(缩放、旋转和平移等)变换(transformation)简易灵活的强大工具,矩阵对象一般与变换对象联合使用。

例如,GraphicsPath对象具有Transform方法,此方法接收Matrix对象作为参数。

参见图14-6。

5.可伸缩区域

GDI+通过对可伸缩区域(scalableregion)的支持极大地扩展了GDI。

在GDI中,区域被存储在设备坐标中,而且,可应用于区域的惟一变换是平移。

而GDI+在全局坐标中存储区域,并且允许区域发生任何可存储在变换矩阵中的变换(如缩放和旋转)。

图14-7显示一个区域在执行三种变换(缩放、旋转和平移)前后的情况。

图14-6路径变换图14-7区域变换图14-8不同透明度

6.α混色

在图14-7中,可以在变换区域(用蓝色阴影画笔填充)中看到未变换区域(用红色填充),这是由GDI+支持的α混色(alphablending,透明混合)实现的。

使用α混色,可以指定填充颜色的透明度。

透明色与背景色相混合———填充色越透明,透出的背景色就越多。

图14-8显示四个用相同颜色(红色)填充、但透明层次不同的椭圆。

7.丰富的图像格式支持

GDI+提供Image、Bitmap和Metafile类,可以用不同的格式加载、保存和操作图像。

GDI+支持BMP、GIF、JPEG、EXIF、PNG、TIFF、ICON、WMF、EMF共9种常见的图像格式。

这些已经被ATL/MFC中的基于GDI+的CImage类所体现。

8.GDI+的不足

虽然,相对于GDI来说,GDI+确实增加了许多新特性,而且功能更强大,使用也更方便。

但是,这并不等于GDI+就能够完全代替GDI。

因为GDI+实际上是GDI的高层封装和功能扩展,GDI+的执行效率一般要低于GDI的。

另外,GDI+不支持图形的位运算,那么就不能进行异或绘图等操作。

而且在VisualC++中,GDI+还不直接支持双缓存机制(如内存DC和显示DC),这将大大影响GDI+在高速图形、图像、动画和视频等方面的应用。

14.2.2编程模式的改变

GDI+的出现,也使基于GDI的编程模式产生了很大变化:

GDI+用一个“无状态模式”,取代了GDI中(需要先将各种工具和项目选入DC对象后,才能进行绘图的)“状态模式”。

主要体现在以下几个方面:

1.DC句柄和图形对象

设备上下文(DC)是GDI中使用的一种结构,用于存储与特定显示设备相关的的绘制工具及属性的信息,用于屏幕显示的DC还与特定窗口相关联。

为了使用GDIAPI进行绘图,必须首先获得一个DC的句柄(HDC),然后将该句柄作为参数,传递给实际进行绘图的GDI函数。

在MFC中,DC及其绘图功能被封装在CDC类中,DC句柄成为了成员变量,绘图函数变成了方法,不再需要显式传递HDC参数。

使用GDI+,不需要再(直接)使用句柄或设备上下文,而是只需(通过HDC)创建一个Graphics对象,然后用熟悉的面向对象方式来调用其中的各种绘图方法,例如:

myGraphicsObject.DrawLine(&pen,x1,y1,x2,y2);

正如DC是GDI的核心,Graphics对象也位于GDI+的核心。

DC和Graphics对象的作用相似,但在使用设备上下文(GDI)的基于句柄的编程模式和使用Graphics对象(GDI+)的面向对象的编程模型之间,存在一些基本的差异。

Graphics对象(像DC一样)与屏幕上的特定窗口关联,并具有指定如何绘制项目的属性(如SmoothingMode和TextRenderingHint)。

但是,Graphics对象不受笔、刷、路径、图像或字体的约束,这与设备上下文不同。

例如,使用设备上下文绘制线条之前,必须先调用SelectObject将笔选入DC中,以使笔对象和DC关联。

在设备上下文中绘制的所有线条均使用该笔,直到选择另一支不同的笔为止。

在GDI+中,将Pen对象作为参数传递给Graphics类的DrawLine等画线方法。

可以在一系列的DrawLine调用的每个调用中,使用不同的Pen对象,而不必将给定的Pen对象与Graphics对象关联。

2.画线的两种方法

下面每个示例都从点(20,10)到点(200,100)绘制一条宽为3的红色线条。

第一个示例调用GDI,第二个示例则通过托管类接口调用GDI+,这里都使用MFC。

也可以不使用MFC,而直接用API来进行GDI+绘图(由于篇幅有限,这里就不介绍了)。

1)用GDI画线

利用MFC进行GDI绘图,步骤与API的差不多,只是MFC将各种GDI功能封装到了不同的类中。

例如,笔的类为CPen、点的类为CPoint、设备上下文的类为CDC。

而且所有的绘图函数都被封在CDC类中,所以只能作为其对象的方法才能被使用,当然也就不用再带HDC句柄作为输入参数了。

CDC*pDC=GetDC();//获取DC对象

CPenpen(PS_SOLID,3,RGB(255,0,0));//创建笔

pDC->SelectObject(&pen);//选笔入DC

pDC->MoveTo(20,10);//将当前点移到直线的起点

pDC->LineTo(200,100);//从当前点画线到直线的终点

2)用GDI+画线

利用MFC进行GDI+绘图,步骤与API的差不多。

只是代码改在OnDraw函数中,而且获取DC句柄的方法不同。

CDC*pDC=GetDC();//获取DC对象

GraphicsmyGraphics(pDC->m_hDC);//利用DC句柄创建图形对象

PenmyPen(Color(255,0,0),3);//创建笔

myGraphics.DrawLine(&myPen,20,10,200,100);//画直线

3.作为参数的绘图工具

前面的示例显示:

在GDI+中,创建和维护Pen对象,可以与提供绘制方法的Graphics对象分开。

同样,创建和维护Brush、GraphicsPath、Image和Font对象也可以与Graphics对象分开,Graphics类提供的许多绘制方法,都将笔、刷、路径、图像和字体等对象,作为参数接收。

例如,Brush对象作为参数传递至FillRectangle方法,GraphicPath对象作为参数传递至DrawPath方法。

同样,Image和Font对象传递至DrawImage和DrawString方法。

这与GDI不同,在GDI中,需要先将笔、刷、路径、图像或字体等GDI工具对象选入DC,然后(API)将DC的句柄作为参数传递至绘制函数或(MFC)采用CDC类对象的函数使用DC中当前的笔、刷、路径、图像或字体来绘图。

4.无当前位置

GDI+从总体上已经放弃了当前位置的概念,如在前面所述的DrawLine方法中线条的起点和终点均被作为参数接收。

这与GDI方案不同,在GDI中,调用MoveToEx(hdc,x1,y1,NULL)或pDC->MoveTo(x1,y1)来设置当前笔位置之后,再调用LineTo(hdc,x2,y2)或pDC->LineTo(x2,y2)来绘制一条从(x1,y1)到(x2,y2)的线条。

5.绘制和填充的不同方法

GDI的Rectangle和Ellipse等函数,可一步完成绘制轮廓和填充内部的功能。

轮廓由当前选定的笔绘制,而内部则由当前选定的刷来填充。

GDI+则必须分别调用绘制轮廓和填充内部的两个不同方法来做到这一点。

例如,Graphics类的DrawRectangle方法将Pen对象作为其参数之一,而FillRectangle方法将Brush对象作为其参数之一。

所以在绘制轮廓和填充图形内部时,GDI+要比GDI更灵活,但也更麻烦。

6.构造区域

GDI提供几种用于创建区域的函数(在MFC中,它们被封装在CRng类里):

CreateRectRgn、CreateEllpticRgn、CreateRoundRectRgn、CreatePolygonRgn和CreatePolyPolygonRgn。

您或许希望GDI+中的Region类也有类似的构造函数,将矩形、椭圆、圆角矩形和多边形作为参数接收,但事实并非如此。

GDI+中的Region类提供一个接收Rectangle对象的构造函数和另一个接收GraphicsPath对象的构造函数。

如果想基于椭圆、圆角矩形或多边形构造区域,可以通过创建一个GraphicsPath对象(可包含椭圆的对象等),然后将其传递至Region构造函数来轻松实现。

GDI+通过组合图形和路径,使得构成复杂区域十分简单。

Region类具有Union和Intersect方法,可用于扩展具有路径的现有区域或其它区域。

GDI+方案一个很好的功能就是GraphicsPath对象在作为参数传递至Region构造函数时不会被破坏(在GDI中,可以使用PathToRegion方法将路径转换为区域,但在此过程中,路径将被破坏)。

另外,GraphicsPath对象在作为参数传递给Union或Intersect方法时也不会被破坏,因此,在一些单独的区域中,可以将给定的路径作为构造块使用。

例如:

Regionregion1(rect1);Regionregion2(rect2);

region1.Union(onePath);region2.Intersect(onePath);

14.3GDI+的MFC编程

本节介绍利用MFC进行GDI+编程的必要的准备,并通过例子说明GDI+编程的具体步骤,最后给出如何解决存在的new操作符问题的方法。

C++封装的GDI+的(英文)帮助内容,位于VS08的“目录/Win32和COM开发/GraphicsandMultimedia/GDI+”,主要的参考资料位于其子目录“GDI+Reference”中。

14.3.1设置与初始化

封装了GDI+API的各种C++类、函数、常量、枚举和结构,都被定义在Gdiplus.h头文件所包含的一系列头文件中。

所以,采用MFC进行GDI+编程,必须包含Gdiplus.h头文件。

从14.1.2的有关GDI+平面API的讨论可知,封装在GDI+类中方法,最后都需要调用GDI+平面API中的相关底层函数,才能完成实际的操作。

所以,为了运行GDI+应用程序,在操作系统平台中,必须安装动态链接库Gdiplus.dll。

对WindowsXP及以上版本,该DLL已经自动被操作系统包含。

该动态链接库所对应的静态库文件为GdiPlus.lib,而且它在VC08及之前的早期版本中不是C++和MFC的默认链接库。

所以,对早期的VC版本必须在项目设置,添加该库作为链接器输入的附加依赖项。

但是对VC08SP1及VC10,该库已经成为标准链接库之一,不必再为链接器输入的附加依赖项添加此库。

因为在Gdiplus.h头文件中,将所有的GDI+的类、函数、常量、枚举和结构等都定义在了命名空间Gdiplus中。

所以,一般在GDI+程序中,都应该使用如下的命名空间声明:

usingnamespaceGdiplus;

1.VC中的设置

为了在MFC应用程序中能使用GDI+,必须包含GDI+头文件、使用GDI+命名空间。

对VC08及之前的版本,还要为项目添加GDI+链接库。

1)包含头文件、使用命名空间——在要使用GDI+的文件(如视图类的头文件或代码文件)头部包含GDI+的头文件:

#include

并加上使用GDI+命名空间的using指令(区分大小写,注意首字母大写):

usingnamespaceGdiplus;

2)添加链接库(对VC08SP1及VC10不必添加)——在VS08及其早期版本中,选“项目/*属性”菜单项,打开项目的属性页窗口,先选“所有配置”,再选“配置属性/链接器/输入”项,在右边上部的“附加依赖项”栏的右边,键入GdiPlus.lib(参见图14-9)后按“应用”钮,最后按“确定”钮关闭对话框。

2.GDI+的初始化与清除

为了在MFC应用程序中使用采用C++封装的GDI+API,必须在MFC项目的应用程序类中,调用GDI+命名空间中的GDI+启动函数GdiplusStartup和GDI+关闭函数GdiplusShutdown,来对GDI+进行初始化(装入动态链接库Gdiplus.dll,或锁定标志+1)和清除(卸载动态链接库Gdiplus.dll,或锁定标志-1)工作。

它们一般分别在应用程序类的InitInstance和ExitInstance重载方法中调用。

图14-9在项目属性对话框中添加静态链接库

函数GdiplusStartup和GdiplusShutdown,都被定义在GdiplusInit.h头文件中:

StatusWINAPIGdiplusStartup(OUTULONG_PTR*token,

constGdiplusStartupInput*input,OUTGdiplusStartupOutput*output);

voidGdiplusShutdown(ULONG_PTRtoken);

其中:

●类型ULONG_PTR,是用无符号长整数表示的指针,被定义在basetsd.h头文件中:

typedef_W64unsignedlongULONG_PTR;

输出参数token(权标),供关闭GDI+的函数使用,所以必须设置为应用程序类的成员变量(或全局变量,不提倡)。

●结构GdiplusStartupInput和GdiplusStartupOutput,都被定义在GdiplusInit.h头文件中。

⏹GDI+启动输入结构指针参数input,一般取默认构造值即可,即(设:

无调试事件回调过程、不抑制背景线程、不抑制外部编解码):

input=GdiplusStartupInput(NULL,FALSE,FALSE);

⏹GDI+启动输出结构指针参数output,一般不需要,取为NULL即可。

注意,采用MFC进行GDI+API编程时,在使用任何GDI+的功能调用之前,必须先调用GDI+启动函数GdiplusStartup来进行初始化GDI+的工作;在完成所有的GDI+功能调用之后,必须调用GDI+关闭函数GdiplusShutdown来进行清除GDI+的工作。

3.过程框图

图14-10是使用MFC进行GDI+编程的设置、准备与初始化过程的逻辑框图。

图14-10GDI+的设置、准备与初始化

14.3.2编程例子

下面通过一个简单的例子,来说明如何使用GDI+进行应用程序开发。

1.创建和设置

创建一个名为Gdip的传统界面MFC单文档应用程序项目,在应用程序类和视图类的CPP代码文件中,包含头文件并使用命名空间:

#include

usingnamespaceGdiplus;

对VC08及之前的版本还需在项目属性中添加链接库GdiPlus.lib。

2.初始化与清除

然后再进行GDI+系统的初始化,这需要在应用程序类CGdipApp中声明一个成员变量:

ULONG_PTRm_gdiplusToken;//ULONGPTR为int64类型

并在该类的初始化函数CGdipApp:

:

InitInstance()中加入以下代码来对GDI+进行初始化:

GdiplusStartupInputgdiplusStartupInput;

GdiplusStartup(&m_gdiplusToken,&gdiplusStartupInput,NULL);

注意:

这两个语句必须加在应用程序类的InitInstance函数中的

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 考试认证 > IT认证

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1