图形容器
图形状态(剪辑区域、转换和质量设置)存储在 图形 对象中。 Windows GDI+ 允许使用容器在 Graphics 对象中临时替换或扩充状态的一部分。 通过调用 图形 对象的 Graphics::BeginContainer 方法来启动容器,并通过调用 Graphics::EndContainer 方法结束容器。 在 Graphics::BeginContainer 和 Graphics::EndContainer之间,对 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);
请注意,在上一示例中,调用 Graphics::BeginContainer 和 Graphics::EndContainer 之间的语句 myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50)
生成与调用 Graphics::EndContainer后所执行的相同语句不同的矩形。 仅水平转换适用于在容器外部进行的 drawRectangle 调用。 这两个转换(200 个单位的水平平移和 100 个单位的垂直转换)都适用于在容器内部进行的 Graphics::D rawRectangle 调用。 下图显示了两个矩形。
容器可以嵌套在容器中。 以下示例在 Graphics 对象中创建容器,并在第一个容器中创建另一个容器。 图形 对象的世界转换是 x 方向的翻译 100 个单位,80 个单位在 y 方向。 第一个容器的世界转换是 30 度的旋转。 第二个容器的世界转换是按 x 方向的 2 乘以 2 的缩放。 对 Graphics::D rawEllipse 方法的调用是在第二个容器中进行的。
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);
下图显示了省略号。
请注意,这三个转换都适用于第二个(最内部)容器中发出的 Graphics::D rawEllipse 调用。 另请注意转换的顺序:首先缩放,然后旋转,然后转换。 最内部的转换首先应用,最外层的转换最后应用。
可以在容器内设置 图形 对象的任何属性(在调用 Graphics::BeginContainer 和 Graphics::EndContainer之间)。 例如,可以在容器内设置剪辑区域。 容器内完成的任何绘图将限制为该容器的剪辑区域,并且也将限制为任何外部容器的剪裁区域和 图形 对象本身的剪辑区域。
到目前为止讨论的属性(世界转换和剪辑区域)由嵌套容器组合。 其他属性暂时替换为嵌套容器。 例如,如果将平滑模式设置为容器中的 SmoothingModeAntiAlias,则在该容器内调用的任何绘图方法都将使用抗锯齿平滑模式,但在调用 Graphics::EndContainer 之后调用的绘图方法将使用调用 Graphics::BeginContainer之前就位的平滑模式。
对于合并 图形 对象和容器的世界转换的另一个示例,假设你想要绘制眼睛并将其放置在一系列人脸上的各个位置。 以下示例绘制以坐标系原点为中心的眼睛。
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 函数的任何代码与 DrawEye 函数执行期间所做的属性设置隔离开来。 例如,DrawEye 函数中的代码设置 Graphics 对象的剪辑区域,但当 DrawEye 将控件返回到调用例程时,剪辑区域将如同调用 DrawEye 之前一样。
下面的示例绘制三个省略号(人脸),每个省略号在内。
// 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)
绘制,该调用绘制以坐标系原点居中的椭圆。 省略号通过设置 图形 对象的世界转换,从工作区的左上角移开。 该语句导致第一个椭圆居中(100,100)。 该语句使第二个椭圆的中心在第一个椭圆的中心右侧为 100 个单位。 同样,第三个椭圆的中心位于第二个椭圆的中心右侧的 100 个单位。
上一示例中的容器用于转换相对于给定椭圆中心的眼睛。 第一个眼睛在椭圆的中心绘制,没有转换,因此 DrawEye 调用不在容器内。 第二只眼睛旋转 40 度,在椭圆中心上方绘制 30 个单位,因此 DrawEye 函数和设置转换的方法在容器内调用。 第三只眼睛被拉伸和旋转,并绘制在椭圆的中心。 与第二只眼睛一样,DrawEye 函数和设置转换的方法在容器内调用。