使用嵌套的图形容器

GDI+ 提供可用于临时替换或扩充 Graphics 对象中状态的一部分的容器。 通过调用 BeginContainer 对象的 Graphics 方法创建容器。 可以重复调用 BeginContainer 以形成嵌套容器。 对 BeginContainer 的每个调用都必须与对 EndContainer的调用配对。

嵌套容器中的转换

以下示例在该 Graphics 对象中创建一个 Graphics 对象和一个容器。 Graphics 对象的世界转换是在 x 方向上平移 100 个单位,在 y 方向上平移 80 个单位。 容器的世界转换是 30 度旋转。 该代码两次调用 DrawRectangle(pen, -60, -30, 120, 60)。 对 DrawRectangle 的第一个调用位于容器内,也就是说,调用发生在 BeginContainerEndContainer的调用之间。 对 DrawRectangle 的第二个调用是在调用 EndContainer之后。

Graphics graphics = e.Graphics;
Pen pen = new Pen(Color.Red);
GraphicsContainer graphicsContainer;
graphics.FillRectangle(Brushes.Black, 100, 80, 3, 3);

graphics.TranslateTransform(100, 80);

graphicsContainer = graphics.BeginContainer();
graphics.RotateTransform(30);
graphics.DrawRectangle(pen, -60, -30, 120, 60);
graphics.EndContainer(graphicsContainer);

graphics.DrawRectangle(pen, -60, -30, 120, 60);
Dim graphics As Graphics = e.Graphics
Dim pen As New Pen(Color.Red)
Dim graphicsContainer As GraphicsContainer
graphics.FillRectangle(Brushes.Black, 100, 80, 3, 3)

graphics.TranslateTransform(100, 80)

graphicsContainer = graphics.BeginContainer()
graphics.RotateTransform(30)
graphics.DrawRectangle(pen, -60, -30, 120, 60)
graphics.EndContainer(graphicsContainer)

graphics.DrawRectangle(pen, -60, -30, 120, 60)

在前面的代码中,从容器内部绘制的矩形首先通过容器的世界转换(旋转)进行转换,然后通过 Graphics 对象的世界转换(平移)进行转换。 从容器外部绘制的矩形仅通过 Graphics 对象的世界转换(平移)进行转换。 下图显示了两个矩形:

显示嵌套容器的 插图。

嵌套容器中的剪切

以下示例演示嵌套容器如何处理裁剪区域。 该代码在该 Graphics 对象中创建 Graphics 对象和容器。 Graphics 对象的剪辑区域是一个矩形,容器的剪辑区域是椭圆。 该代码对 DrawLine 方法进行两次调用。 对 DrawLine 的第一次调用位于容器内部,对 DrawLine 的第二次调用位于容器外部(调用 EndContainer后)。 第一行以两个剪切区域的交集进行剪切。 第二行仅以 Graphics 对象的矩形剪切区域进行剪切。

Graphics graphics = e.Graphics;
GraphicsContainer graphicsContainer;
Pen redPen = new Pen(Color.Red, 2);
Pen bluePen = new Pen(Color.Blue, 2);
SolidBrush aquaBrush = new SolidBrush(Color.FromArgb(255, 180, 255, 255));
SolidBrush greenBrush = new SolidBrush(Color.FromArgb(255, 150, 250, 130));

graphics.SetClip(new Rectangle(50, 65, 150, 120));
graphics.FillRectangle(aquaBrush, 50, 65, 150, 120);

graphicsContainer = graphics.BeginContainer();
// Create a path that consists of a single ellipse.
GraphicsPath path = new GraphicsPath();
path.AddEllipse(75, 50, 100, 150);

// Construct a region based on the path.
Region region = new Region(path);
graphics.FillRegion(greenBrush, region);

graphics.SetClip(region, CombineMode.Replace);
graphics.DrawLine(redPen, 50, 0, 350, 300);
graphics.EndContainer(graphicsContainer);

graphics.DrawLine(bluePen, 70, 0, 370, 300);
Dim graphics As Graphics = e.Graphics
Dim graphicsContainer As GraphicsContainer
Dim redPen As New Pen(Color.Red, 2)
Dim bluePen As New Pen(Color.Blue, 2)
Dim aquaBrush As New SolidBrush(Color.FromArgb(255, 180, 255, 255))
Dim greenBrush As New SolidBrush(Color.FromArgb(255, 150, 250, 130))

graphics.SetClip(New Rectangle(50, 65, 150, 120))
graphics.FillRectangle(aquaBrush, 50, 65, 150, 120)

graphicsContainer = graphics.BeginContainer()
' Create a path that consists of a single ellipse.
Dim path As New GraphicsPath()
path.AddEllipse(75, 50, 100, 150)

' Construct a region based on the path.
Dim [region] As New [Region](path)
graphics.FillRegion(greenBrush, [region])

graphics.SetClip([region], CombineMode.Replace)
graphics.DrawLine(redPen, 50, 0, 350, 300)
graphics.EndContainer(graphicsContainer)

graphics.DrawLine(bluePen, 70, 0, 370, 300)

下图显示了两条截断的线:

显示包含经过剪切的行的嵌套容器的插图。

如前两个示例所示,转换和剪切区域在嵌套容器中累积。 如果您设置了容器和 Graphics 对象的世界变换,那么这两个变换都会应用于在容器内部绘制的项目。 容器的转换首要被应用,而 Graphics 对象的转换其次被应用。 如果设置了容器和 Graphics 对象的剪切区域,则将以两个剪切区域的交集剪切从容器内部绘制的项。

嵌套容器中的质量设置

嵌套容器中的质量设置(SmoothingModeTextRenderingHint等)不是累积的:相反,容器的质量设置暂时替换 Graphics 对象的质量设置。 创建新容器时,该容器的质量设置将设置为默认值。 例如,假设你有一个 Graphics 对象,其平滑模式为 AntiAlias。 创建容器时,容器内的平滑模式是默认平滑模式。 您可以自由地设置容器的平滑模式,容器内的任何绘制项目将按照您所设置的模式进行绘制。 调用 EndContainer 后绘制的项目将按照调用 AntiAlias之前所设置的平滑模式(BeginContainer)进行绘制。

嵌套容器的几个层

您在 Graphics 对象中可以使用多个容器,而不仅限于一个。 可以创建一个容器序列,每个容器都嵌套在前一个容器中,并且可以为每个嵌套容器指定世界变换、剪辑区域和质量设置。 如果从最内部容器内部调用绘图方法,则转换将按顺序应用,从最内部的容器开始,以最外层容器结尾。 从最内层的容器中绘制的项将以所有剪切区域的交集进行剪切。

以下示例创建一个 Graphics 对象并将其文本呈现提示设置为 AntiAlias。 该代码创建两个容器,一个容器嵌套在另一个容器中。 外部容器的文本呈现提示设置为 SingleBitPerPixel,内部容器的文本呈现提示设置为 AntiAlias。 该代码绘制三个字符串:一个来自内部容器,一个来自外部容器,一个来自 Graphics 对象本身。

Graphics graphics = e.Graphics;
GraphicsContainer innerContainer;
GraphicsContainer outerContainer;
SolidBrush brush = new SolidBrush(Color.Blue);
FontFamily fontFamily = new FontFamily("Times New Roman");
Font font = new Font(fontFamily, 36, FontStyle.Regular, GraphicsUnit.Pixel);

graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;

outerContainer = graphics.BeginContainer();

graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;

innerContainer = graphics.BeginContainer();
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
graphics.DrawString(
   "Inner Container",
   font,
   brush,
   new PointF(20, 10));
graphics.EndContainer(innerContainer);

graphics.DrawString(
   "Outer Container",
   font,
   brush,
   new PointF(20, 50));

graphics.EndContainer(outerContainer);

graphics.DrawString(
   "Graphics Object",
   font,
   brush,
   new PointF(20, 90));
Dim graphics As Graphics = e.Graphics
Dim innerContainer As GraphicsContainer
Dim outerContainer As GraphicsContainer
Dim brush As New SolidBrush(Color.Blue)
Dim fontFamily As New FontFamily("Times New Roman")
Dim font As New Font( _
   fontFamily, _
   36, _
   FontStyle.Regular, _
   GraphicsUnit.Pixel)

graphics.TextRenderingHint = _
System.Drawing.Text.TextRenderingHint.AntiAlias

outerContainer = graphics.BeginContainer()

graphics.TextRenderingHint = _
    System.Drawing.Text.TextRenderingHint.SingleBitPerPixel

innerContainer = graphics.BeginContainer()
graphics.TextRenderingHint = _
    System.Drawing.Text.TextRenderingHint.AntiAlias
graphics.DrawString( _
   "Inner Container", _
   font, _
   brush, _
   New PointF(20, 10))
graphics.EndContainer(innerContainer)

graphics.DrawString("Outer Container", font, brush, New PointF(20, 50))

graphics.EndContainer(outerContainer)

graphics.DrawString("Graphics Object", font, brush, New PointF(20, 90))

下图显示了三个字符串。 从内部容器和 Graphics 对象中绘制的字符串通过抗锯齿技术进行平滑处理。 从外部容器中绘制的字符串不会通过抗锯齿来平滑,因为 TextRenderingHint 属性设置为 SingleBitPerPixel

插图,显示从嵌套容器绘制的字符串。

另请参阅