GDI+学习之路8--图形容器

       图片状态(裁剪区域、变形、质量设置等)存储于Graphics对象中。GDI+ 允许您采用一个容器临时替换或者扩充一个Graphics对象的状态。调用Graphics对象的BeginContainer方法开始一个容器,直至调用EndContainer方法终止一个容器。在这期间,您对于属于该容器的Graphics对象进行的任何状态改变都不会覆盖掉Graphics对象现存的状态。

下面的例子在一个Graphics对象中创建一个容器。Graphics对象的世界变换是向右平移200个单位,而容器的世界变换是向下平移100个单位。

myGraphics.TranslateTransform(200.0f, 0.0f);

 

myGraphicsContainer = myGraphics.BeginContainer();

   myGraphics.TranslateTransform(0.0f, 100.0f);

   myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50);

myGraphics.EndContainer(myGraphicsContainer);

 

myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50);

       注意,在前面的例子中, 置于BeginContainerEndContainer调用之间的语句myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50)产生的矩形和EndContainer调用之后的同样的语句产生了不同的2个矩形。应用于DrawRectangle调用的两种变换(水平平移200个单位和垂直平移100个单位)都在容器内部进行。下图显示了这两个矩形。

   

       容器可以与容器嵌套。下面的例子在一个Graphics对象内创建一个容器,紧接着在前一个容器中再创建另一个容器。Graphics容器的世界变换是沿X轴平移100个单位然后沿Y轴平移80个单位。第一个容器的世界变换是旋转30度角。第二个容器的世界变换是沿X轴缩放2倍单位。在第二个容器中调用DrawEllipse方法。

myGraphics.TranslateTransform(100.0f, 80.0f, MatrixOrderAppend);

 

container1 = myGraphics.BeginContainer();

   myGraphics.RotateTransform(30.0f, MatrixOrderAppend);

 

   container2 = myGraphics.BeginContainer();

      myGraphics.ScaleTransform(2.0f, 1.0f);

      myGraphics.DrawEllipse(&myPen, -30, -20, 60, 40);

   myGraphics.EndContainer(container2);

 

myGraphics.EndContainer(container1);

注意,所有的变换都应用于第二个(最里面的)容器里面的DrawEllipse调用。同时注意,变换的顺序:首先缩放,然后是旋转,然后才是平移。最内层的变换最先被执行,最外层的变换最迟执行。

在容器内部(在BeginContainerEndContainer调用之间)可以对Graphics对象的任意属性进行设置。例如,可以在容器内设置一个剪切区域。容器内的任何绘图操作都将被该容器的剪切区域所裁剪,同时也会被外层容器以及Graphics对象本身的剪切区域所裁剪。

关于属性的讨论已经很深入了,嵌套容器中的世界变换和裁剪区域。其他属性则由嵌套容器临时替换。例如,当您在一个容器中通过SmoothingModeAntiAlias设置了平滑模式后,在容器内部的任何绘图操作都将采用这个平滑模式,但是在EndContainer调用之后的绘图操作则采用BeginContainer调用之前的平滑模式。

再举个容器内部一个Graphics对象的世界变换的例子,假设立希望绘制一只眼睛然后将它放到若干脸部的不同位置。下面的例子将在坐标系统原点位置绘制一只眼睛。

void DrawEye(Graphics* pGraphics)

{

   GraphicsContainer eyeContainer;

   eyeContainer = pGraphics->BeginContainer();

 

   Pen myBlackPen(Color(255, 0, 0, 0));

   SolidBrush myGreenBrush(Color(255, 0, 128, 0));

   SolidBrush myBlackBrush(Color(255, 0, 0, 0));

 

   GraphicsPath myTopPath;

   myTopPath.AddEllipse(-30, -50, 60, 60);

 

   GraphicsPath myBottomPath;

   myBottomPath.AddEllipse(-30, -10, 60, 60);

 

   Region myTopRegion(&myTopPath);

   Region myBottomRegion(&myBottomPath);

 

   // Draw the outline of the eye.

   // The outline of the eye consists of two ellipses.

   // The top ellipse is clipped by the bottom ellipse, and

   // the bottom ellipse is clipped by the top ellipse.

   pGraphics->SetClip(&myTopRegion);

   pGraphics->DrawPath(&myBlackPen, &myBottomPath);

   pGraphics->SetClip(&myBottomRegion);

   pGraphics->DrawPath(&myBlackPen, &myTopPath);

 

   // Fill the iris.

   // The iris is clipped by the bottom ellipse.

   pGraphics->FillEllipse(&myGreenBrush, -10, -15, 20, 22);

 

   // Fill the pupil.

   pGraphics->FillEllipse(&myBlackBrush, -3, -7, 6, 9);

 

   pGraphics->EndContainer(eyeContainer);

}

       上面例子中的DrawEye函数接受一个Graphics对象地址,然后立即在该Graphics对象中创建一个容器。容器使得DrawEye函数内部的代码调用与在执行过程中的属性设置相脱离。例如,DrawEys函数内部代码设置了Graphics对象的剪切区域,但是当DrawEys将控制权返回给调用例程后,裁剪区域将恢复为DrawEye调用之前的状态。

下面的代码演示了绘制3个椭圆(脸),每个内部都有一只眼睛。

// Draw an ellipse with center at (100, 100).

myGraphics.TranslateTransform(100.0f, 100.0f);

myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);

 

// Draw the eye at the center of the ellipse.

DrawEye(&myGraphics);

 

// Draw an ellipse with center at 200, 100.

myGraphics.TranslateTransform(100.0f, 0.0f, MatrixOrderAppend);

myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);

 

// Rotate the eye 40 degrees, and draw it 30 units above

// the center of the ellipse.

myGraphicsContainer = myGraphics.BeginContainer();

   myGraphics.RotateTransform(-40.0f);

   myGraphics.TranslateTransform(0.0f, -30.0f, MatrixOrderAppend);

   DrawEye(&myGraphics);

myGraphics.EndContainer(myGraphicsContainer);

 

// Draw a ellipse with center at (300.0f, 100.0f).

myGraphics.TranslateTransform(100.0f, 0.0f, MatrixOrderAppend);

myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);

 

// Stretch and rotate the eye, and draw it at the

// center of the ellipse.

myGraphicsContainer = myGraphics.BeginContainer();

   myGraphics.ScaleTransform(2.0f, 1.5f);

   myGraphics.RotateTransform(45.0f, MatrixOrderAppend);

   DrawEye(&myGraphics);

myGraphics.EndContainer(myGraphicsContainer);

       上例中,所有的椭圆都是采用DrawEllipse(&myBlackPen, -40, -60, 80, 120)调用绘制的,该语句将在坐标系统的原点位置绘制椭圆。通过设置Graphics对象的世界变换来将椭圆的工作区从左上角移开。该语句使得第一个椭圆在(100,100)的位置居中,使得第二个椭圆在第一个椭圆中心位置向右平移了100个单位。同样地,第三个椭圆的中心又在第二个椭圆的基础上向右平移了100个单位。

上例中的容器用于相对于给定椭圆中心对眼睛进行平移。第一只绘制于椭圆中心位置的眼睛没有任何变换,因此没有将DrawEye调用放到容器中。第二只眼睛旋转40度后又相对于椭圆中心向上平移了30个单位,因此DrawEye函数调用和变换等操作是在容器内部进行的。第三个眼睛进行了缩放、旋转操作然后绘制于椭圆中心位置。与第二只眼睛类似的,DrawEye函数调用和变换等操作也是置于容器内部的。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值