图形容器
图形状态(剪裁区域、转换和质量设置)存储在 Graphics 对象中。 Windows GDI+ 允许使用容器暂时替换或增强 图形 对象中的部分状态。 通过调用 Graphics 对象的 Graphics::BeginContainer 方法启动容器,并通过调用 Graphics::EndContainer 方法结束容器。 在 Graphics::BeginContainer 和 Graphics::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);
请注意,在前面的示例中,在对 Graphics::BeginContainer 和 Graphics::EndContainer 的调用之间进行的 语句myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50)
生成的矩形与在调用 Graphics::EndContainer 后执行的相同语句不同。 只有水平转换适用于在容器外部进行的 DrawRectangle 调用。 这两种转换(200 个单位的水平平移和 100 个单位的垂直平移)适用于在容器内进行的 Graphics::D rawRectangle 调用。 下图显示了两个矩形。
容器可以嵌套在容器中。 以下示例在 Graphics 对象中创建一个容器,在第一个容器中创建另一个容器。 Graphics 对象的世界转换是 x 方向的平移 100 个单位,在 y 方向转换 80 个单位。 第一个容器的世界转换是 30 度的旋转。 第二个容器的世界转换是在 x 方向上按 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 对象的任何属性都可以在容器内设置, (调用 Graphics::BeginContainer 和 Graphics::EndContainer) 。 例如,可以在容器中设置剪辑区域。 在容器内完成的任何绘图将限制为该容器的剪裁区域,还将限制为任何外部容器的剪裁区域和 Graphics 对象本身的剪裁区域。
到目前为止讨论的属性(世界转换和剪辑区域)由嵌套容器组合。 其他属性暂时替换为嵌套容器。 例如,如果在容器中将平滑模式设置为 SmoothingModeAntiAlias,则在该容器内调用的任何绘图方法都将使用抗锯齿平滑模式,但在 Graphics::EndContainer 之后调用的绘图方法将使用调用 Graphics::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 函数的任何代码与执行 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)
将绘制一个以坐标系原点为中心的椭圆。 通过设置 Graphics 对象的世界转换,省略号从工作区的左上角移开。 语句使第一个椭圆居中 (100, 100) 。 语句使第二个椭圆的中心在第一个椭圆的中心右侧为 100 个单位。 同样,第三个椭圆的中心在第二个椭圆的中心右侧为 100 个单位。
上一示例中的容器用于转换相对于给定椭圆中心的眼睛。 第一只眼睛在椭圆的中心绘制,不进行转换,因此 DrawEye 调用不在容器内。 第二只眼睛旋转 40 度,在椭圆中心上方绘制 30 个单位,因此 DrawEye 函数和设置转换的方法在容器内调用。 第三只眼睛在椭圆的中心拉伸、旋转和绘制。 与第二只眼睛一样,DrawEye 函数和设置转换的方法在容器内调用。