windows编程技术15GDI+高级编程.docx
《windows编程技术15GDI+高级编程.docx》由会员分享,可在线阅读,更多相关《windows编程技术15GDI+高级编程.docx(96页珍藏版)》请在冰豆网上搜索。
windows编程技术15GDI+高级编程
第15章GDI+高级编程
本章介绍GDI+的路径、区域、变换、图像处理和图元文件等高级编程内容。
路径由许多不同类型的点所构成,用于表示复杂的不规则图形。
区域是由矩形、椭圆、多边形等几何形状组合构成的一种封闭图形,可用于复杂图形的绘制、剪裁和击中测试等。
Graphics类可对绘制的图形进行平移、旋转和伸缩变换。
矩阵类Matrix则可用于图形、图像、颜色、路径、区域等对象的变换。
GDI+的图像处理功能强大,可以加载、保存和操作多种格式的图像。
GDI+的图元文件格式为EMF+,可用来保存和重放绘图记录,也能用于交互绘图的重绘操作。
15.1路径
路径(path)是一系列相互连接的直线和曲线,由许多不同类型的点所构成,用于表示复杂的不规则图形,也叫做图形路径(graphicspath)。
路径可以被画轮廓和填充,也可以用于创建区域和路径渐变刷等。
在GDI中也有路径(本书未讲),但是它只是作为DC的一种状态才能存在。
独立的路径对象,则是GDI+的新特点。
15.1.1图形路径
在GDI+中,路径由图形路径类GraphicsPath表示,它是GDI+基类GdiplusBase的直接派生类。
1.构造函数
GraphicsPath类有三个构造函数:
GraphicsPath(FillModefillMode=FillModeAlternate);//构造一个空路径
GraphicsPath(constPoint*points,constBYTE*types,INTcount,FillModefillMode=FillModeAlternate);//构造含指定整数型点数组的路径
GraphicsPath(constPointF*points,constBYTE*types,INTcount,FillModefillMode=FillModeAlternate);//构造含指定浮数型点数组的路径
其中:
●填充模式参数fillMode在上一章的画填充多边形和曲线时已经讲过,枚举类型FillMode除了可取这里的默认值FillModeAlternate(交替填充模式)之外,还有一个可取的值是FillModeWinding(环绕替填充模式)。
●点数组参数points,可以是整数类型的,也可以是浮点数类型的。
●点类型数组参数types,主要点类型有路径起点、直线端点和贝塞尔点。
●计数参数count为数组points和types的元素数,这两种数组中的元素数必须一致。
2.点的种类
构造函数中,点的类型取值为枚举类型PathPointType常量;
typedefenum{
PathPointTypeStart=0,//起点
PathPointTypeLine=1,//直线端点
PathPointTypeBezier=3,//贝塞尔(曲线的控制)点
PathPointTypePathTypeMask=0x7,//点类型掩码(只保留低三位)
PathPointTypePathDashMode=0x10,//未使用
PathPointTypePathMarker=0x20,//标记点(用于路径分段)
PathPointTypeCloseSubpath=0x80,//闭子路径(图形)的终点
PathPointTypeBezier3=3//同PathPointTypeBezier
}PathPointType;
其中,主要的点类型有起点、直线端点、贝塞尔点、标记点和闭子路径终点。
其他曲线类型(如弧、椭圆和基样条曲线等)在路径中都是用贝塞尔曲线来表示的。
路径是由点组成的,但这里的点,不光指其坐标位置,还包括点的类型。
同样的点坐标,不同的点类型,最后得到的路径可能大相径庭。
例如,同一组点,定义两个路径,一个的点类型全是直线端点,另一个的起点之后有3个贝塞尔点,最后才是两个直线点(参见图15-1,其中自定义画点列方法DrawPoints,在画曲线时用过,源码参见14.6.5的1.):
Pointpoints[]={Point(40,140),Point(275,200),
Point(105,225),Point(190,300),Point(50,350),
Point(20,180)};//定义点数组
//定义点类型数组(为了节省篇幅,有些直接用了枚举的整数值)
BYTElineTypes[]={PathPointTypeLine,1,1,1,1,1};
BYTEtypes[]={PathPointTypeStart,PathPointTypeBezier,
3,3,PathPointTypeLine,1};
GraphicsPathpath1(points,lineTypes,6),//创建直线路径
path2(points,types,6);//创建复合路径
Graphicsgraph(pDC->m_hDC);//创建图形对象
//填充直线路径、画直线、画点列
graph.FillPath(&SolidBrush(Color:
:
Lime),&path1);
graph.DrawLines(&Pen(Color:
:
Violet),points,6);
DrawPoints(graph,Color:
:
Red,4,points,6);
graph.TranslateTransform(300,0);//右移300像素
//填充复合路径、画直线、画点列
graph.FillPath(&SolidBrush(Color:
:
Aqua),&path2);
graph.DrawLines(&Pen(Color:
:
Magenta),points,6);
DrawPoints(graph,Color:
:
Red,4,points,6);
图15-1点类型
3.路径的构成
前面已经讲过,路径是一系列相互连接的直线和曲线,它们最终都是由有序点列所组成。
可以利用GraphicsPath类的后两个构造函数,将点数组直接加入路径中。
不过,路径中的直线和曲线等图形,一般是通过调用路径类的若干添加图形方法给加进来的。
每个被加入的图形都可以是一个子路径(subpath)。
路径对象,会将被加入图形(包括封闭图形)中的点尾首相接,连成一条完整的路径。
在路径中的图形都是开图形(起点和终点可能是同一个点,例如矩形、椭圆、多边形和闭曲线等),可以调用图形路径类的CloseFigure或CloseAllFigures方法:
StatusCloseFigure(VOID);//关闭当前子路径
StatusCloseAllFigures(VOID);//关闭所有子路径
来显式闭合路径对象中的当前子路径或所有子路径。
例如(参见图15-2):
Graphicsgraph(pDC->m_hDC);//创建图形像对象
Penpen(Color:
:
Blue);//定义蓝色笔
GraphicsPathpath;//创建路径对象
path.AddLine(10.0f,50.0f,200.0f,50.0f);//加水平直线
//path.StartFigure();//断开两条直线之间的连接(即分成两个子路径)
path.AddLine(60.0f,10.0f,60.0f,80.0f);//加垂直直线
path.AddEllipse(10,100,200,120);//加椭圆
path.AddBezier(Point(220,200),Point(250,150),
Point(300,50),Point(400,200));//加贝塞尔曲线
intn=path.GetPointCount();//获取路径中的点数
Point*points=newPoint[n];//新建点数组
path.GetPathPoints(points,n);//获取路径中的点
//path.SetFillMode(FillModeWinding);//设置填充模式
//填充(开)路径
//graph.FillPath(&SolidBrush(Color:
:
Aqua),&path);
graph.DrawLines(&Pen(Color:
:
Green),points,n);//画折线
//path.CloseAllFigures();//关闭所有子路径
graph.DrawPath(&pen,&path);//画路径轮廓
DrawPoints(graph,Color:
:
Red,4,points,n);//画路径中的点
4.添加图形
图形路径类GraphicsPath中的下列方法,用于添加图形到路径中(重载和参数都与Graphics类中对应的绘图方法相同,但是前缀都改成了Add):
点列与路径填充(开)路径
开(子)路径闭(子)路径
图15-2路径的构成
●加直线:
AddLine
●加折线:
AddLines
●加多边形:
AddPolygon
●加矩形:
AddRectangle
●加矩形组:
AddRectangles
●加弧:
AddArc
●加饼:
AddPie
●加椭圆:
AddEllipse
●加贝塞尔曲线:
AddBezier
●加相连的多段贝塞尔曲线:
AddBeziers
●加基样条曲线:
AddCurve
●加闭基样条曲线:
AddClosedCurve
●加串:
AddString
5.绘制路径
可以用Graphics类的方法DrawPath来画路径的轮廓,用其另一个方法FillPath来填充路径的内部(对开路径,会先自动封闭,然后再进行填充):
StatusDrawPath(constPen*pen,constGraphicsPath*path);
StatusFillPath(constBrush*brush,constGraphicsPath*path);
当然你也可以用GraphicsPath类的方法SetFillMode和GetFillMode来设置不同的填充模式或者获取当前的填充模式:
StatusSetFillMode(FillModefillmode);
FillModeGetFillMode(VOID);
关于画路径轮廓和填充路径的例子,前面已经有了很多,这里就不再列举了。
6.获取点信息
在创建路径并添加各种几何图形或字符串之后,我们可以调用如下一些GraphicsPath类的方法,来获取路径中的点的信息。
包括点的坐标信息和点的类型信息:
INTGetPointCount(VOID);//获取路径中的总点数
StatusGetPathPoints(Point*points,INTcount);//获取路径中(指定数目的)整数点数组
StatusGetPathPoints(PointF*points,INTcount);//获取路径中(指定数目的)浮点数点数组
StatusGetPathTypes(BYTE*types,INTcount);//获取路径中(指定数目的)点类型数组
例如:
GraphicsPathpath;
……//添加若干图形到路径
intn=path.GetPointCount();
Point*points=newPoint[n];
path.GetPathPoints(points,n);
graph.DrawLines(&Pen(Color:
:
Green),points,n);
DrawPoints(graph,Color:
:
Red,4,points,n);
15.1.2路径渐变刷
路径可以表示复杂的图形,可以用于绘制这些图形的轮廓和填充,也可以用于创建区域(在下一节介绍)和颜色渐变刷。
后者在前面美术字部分的彩心字符串例中(参见14.8.35.),我们已经用过。
与其它具体刷(如实心刷、条纹刷和纹理刷等)类一样,路径渐变(梯度)刷类PathGradientBrush,也是Brush类的派生类。
它有3个构造函数:
PathGradientBrush(constGraphicsPath*path);
PathGradientBrush(constPoint*points,INTcount,
WrapModewrapMode=WrapModeClamp);
PathGradientBrush(constPointF*points,INTcount,
WrapModewrapMode=WrapModeClamp);
第一个构造函数从现有路径对象来创建画刷,后两个则是从整数或浮点数点集来直接创建画刷,而且它们两个还有一个重复排列的输入参数wrapMode,默认值为WrapModeClamp(不重复排列)。
路径刷的颜色,一般是从路径点(周边轮廓)向路径中心渐变。
路径刷的默认中心为路径的形心,可以用路径刷方法SetCenterPoint来重新设置:
StatusSetCenterPoint(constPoint&point);
StatusSetCenterPoint(constPointF&point);
其中的中心点,可以位于任何位置,包括在路径的范围之外。
对应的获取刷中心的方法是:
StatusGetCenterPoint(Point*point);
StatusGetCenterPoint(PointF*point);
其它常用的路径刷方法有:
StatusSetCenterColor(constColor&color);//设置刷中心颜色
StatusSetSurroundColors(constColor*colors,INT*count);//设置路径点颜色
StatusGetCenterColor(Color*color);//获取刷中心颜色
INTGetSurroundColorCount(VOID);//获取路径点颜色数目
StatusGetSurroundColors(Color*colors,INT*count);//获取路径点颜色数组
其中,路径刷的中心色和路径点色,默认都为背景色(白色)。
例如(用路径刷画五角星,参见图15-3):
INTcount=10;
Pointpoints[]={Point(100,0),Point(122,69),
Point(195,69),Point(137,111),Point(159,181),
Point(100,138),Point(41,181),Point(63,111),
Point(5,69),Point(78,69)};
GraphicsPathpath;
path.AddPolygon(points,count);
Graphicsgraph(pDC->m_hDC);
PathGradientBrushpgBrush(&path);
pgBrush.SetCenterColor(Color:
:
Red/*Green*/);
graph.FillPath(&pgBrush,&path);
Colorcols[]={Color:
:
Black,Color:
:
Green,Color:
:
Blue,
Color:
:
White,Color:
:
Black,Color:
:
Green,Color:
:
Blue,
Color:
:
White,Color:
:
Black,Color:
:
Green};
/*Colorcols[]={Color:
:
Cyan,Color:
:
Aqua,Color:
:
Blue,
Color:
:
Chartreuse,Color:
:
Coral,Color:
:
CadetBlue,
Color:
:
HotPink,Color:
:
Turquoise,Color:
:
LightSkyBlue,
Color:
:
DeepPink};
pgBrush.SetCenterColor(Color:
:
White);*/
pgBrush.SetSurroundColors(cols,&count);
graph.TranslateTransform(200.0f,0);
graph.FillPath(&pgBrush,&path);
for(inti=0;icols[i]=Color(rand()%255,rand()%255,rand()%255);
pgBrush.SetSurroundColors(cols,&count);
pgBrush.SetCenterColor(Color(rand()%255,rand()%255,
rand()%255));
graph.TranslateTransform(-200.0f,200.0f);
graph.FillPath(&pgBrush,&path);
for(inti=0;icols[i]=Color(rand()%255,rand()%255,rand()%255);
pgBrush.SetSurroundColors(cols,&count);
pgBrush.SetCenterColor(Color(rand()%255,rand()%255,
rand()%255));
graph.TranslateTransform(200.0f,0.0f);
graph.FillPath(&pgBrush,&path);
输出结果为(由于下排的两个五角星,使用的是随机色,所以每次刷新时,颜色都不一样)
a)b)
图15-3路径刷五角星
a)上排左为红心和白边点,上排右为红心和和黑、绿、蓝、白边点
b)上排的左右皆为绿心,边点色同a)的
a)和b)下排的中心点和边点都为随机色,刷新后颜色会变
如果将边点全改成红色、绿色或蓝色,中心改为白色,则输出效果如图15-4所示。
图15-4路径刷五角星(白心,红、绿、蓝边)
又例如(用路径刷画平铺六边形,参见图15-5和图15-6):
#include
……
voidFillHexagon(HDChdc,RectF&rect)//用路径刷画平铺六边形
{
floatradian=3.1415926f/180.0f;
floatl=50.0f,fh=l*sin(60.0f*radian);
PointFpts[]={PointF(50.0f,0.0f),
PointF(50.0f*1.5f,0.0f),PointF(50.0f,0.0f),
PointF(50.0f/2.0f,-fh),PointF(-50.0f/2.0f,-fh),
PointF(-50.0f,0.0f),PointF(-50.0f*1.5f,0.0f),
PointF(-50.0f,0.0f),PointF(-50.0f/2.0f,fh),
PointF(50.0f/2.0f,fh)};
PathGradientBrushpgBrush(pts,10);
pgBrush.SetWrapMode(WrapModeTile);
Graphicsgraph(hdc);
图15-5六边形坐标
pgBrush.SetCenterColor(Color:
:
Red);
graph.FillRectangle(&pgBrush,rect);
graph.TranslateTransform(75.0f,fh);
pgBrush.SetCenterColor(Color:
:
Green);
graph.FillRectangle(&pgBrush,-75.0f,-fh,rect.Width,
rect.Height);
}
voidCGdipDrawView:
:
OnDraw(CDC*pDC){
……
RECTsrect;
GetClientRect(&srect);
RectFrect(0.0f,0.0f,REAL(srect.right),
REAL(srect.bottom));
FillHexagon(pDC->m_hDC,rect);//用路径刷画平铺六边形
}
图15-6路径刷平铺六边形
15.2区域
区域(region)由若干几何形状所构成的一种封闭图形,主要用于复杂图形的绘制、图形输出的剪裁和鼠标击中的测试等。
最简单也是最常用的区域是矩形,其次是椭圆和多边形以及它们的组合。
这些也正是GDI所支持的区域类型。
GDI+中的区域是一种显示表面的范围(anareaofthedisplaysurface),可以是任意形状(的图形的组合),边界一般为路径。
除了上面所讲的矩形、椭圆、多边形之外,其边界还可以含直线、折线、弧、贝塞尔曲线和基样条曲线等开图形,其内容还可以包含饼、闭贝塞尔曲线和基样条曲线等闭图形。
在GDI+中,区域所对应的类是Region,它是一个独立的类(没有基类,也没有派生类)。
但是它有若干相关的类,如各种图形类和图形路径类等。
15.2.1构造函数
Region类有6个构造函数:
Region(VOID);//创建一个空区域
Region(constRect&rect);//创建一个整数型矩形区域
Region(constRectF&rect);//创建一个浮点数型矩形区域
Region(constGraphicsPath*path);//由图形路径来创建区域
Region(constBYTE*regionData,INTsize);//由(另一)区域的数据构造区域
Region(HRGNhRgn);//由GDI的区域句柄构造区域
其中,创建矩形区域最简单,由路径创建区域最常用。
15.2.2其他方法
区域类的其他方法有:
Region*Clone(VOID);//克隆(复制)
//判断本区域是否与另一区域region相等,g用于坐标计算:
BOOLEquals(constR