Usando contêineres de elementos gráficos aninhados

O GDI+ fornece contêineres que você pode usar para substituir ou aumentar temporariamente parte do estado em um Graphics objeto. Você cria um contêiner chamando o BeginContainer método de um Graphics objeto. Você pode chamar BeginContainer repetidamente para formar contêineres aninhados. Cada chamada para deve ser emparelhada com uma chamada para BeginContainerEndContainer.

Transformações em contêineres aninhados

O exemplo a seguir cria um objeto e um Graphics contêiner dentro desse Graphics objeto. A transformação do mundo do Graphics objeto é uma translação: 100 unidades na direção x e 80 unidades na direção y. A transformação global do contêiner é uma rotação de 30 graus. O código faz a chamada DrawRectangle(pen, -60, -30, 120, 60) duas vezes. A primeira chamada para é dentro do contêiner, ou seja, a chamada está entre as chamadas para DrawRectangleBeginContainer e EndContainer. A segunda chamada para é após a chamada para DrawRectangleEndContainer.

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)

No código anterior, o retângulo desenhado de dentro do recipiente é transformado primeiro pela transformação do mundo do recipiente (rotação) e depois pela transformação do mundo do Graphics objeto (translação). O retângulo desenhado de fora do recipiente é transformado apenas pela transformação do mundo do Graphics objeto (tradução). A ilustração a seguir mostra os dois retângulos:

Illustration that shows nested containers.

Recorte em contêineres aninhados

O exemplo a seguir demonstra como contêineres aninhados lidam com áreas de recorte. O código cria um objeto e um Graphics contêiner dentro desse Graphics objeto. A região de recorte do objeto é um retângulo e a região de recorte do Graphics contêiner é uma elipse. O código faz duas chamadas para o DrawLine método. A primeira chamada para está dentro do contêiner e a segunda chamada para está fora do contêiner (após a chamada para DrawLineDrawLineEndContainer). A primeira linha é recortada pela interseção das duas áreas de recorte. A segunda linha é cortada somente pela região de recorte retangular do Graphics objeto.

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)

A ilustração a seguir mostra as duas linhas cortadas:

Illustration that shows a nested container with clipped lines.

Como os dois exemplos anteriores mostram, as transformações e áreas de recorte são cumulativas em contêineres aninhados. Se você definir as transformações de mundo do contêiner e do Graphics objeto, ambas as transformações serão aplicadas a itens desenhados de dentro do contêiner. A transformação do contêiner será aplicada primeiro, e a transformação do Graphics objeto será aplicada em segundo. Se você definir as regiões de recorte do contêiner e do objeto, os Graphics itens desenhados de dentro do contêiner serão cortados pela interseção das duas regiões de recorte.

Configurações de qualidade em contêineres aninhados

As configurações de qualidade (SmoothingMode, e afins) em contêineres aninhados não são cumulativas, em vez disso, TextRenderingHintas configurações de qualidade do contêiner substituem temporariamente as configurações de qualidade de um Graphics objeto. Quando você cria um novo contêiner, as configurações de qualidade do contêiner são definidas com valores padrão. Por exemplo, suponha que você tenha um objeto com um Graphics modo de suavização de AntiAlias. Quando você cria um contêiner, o modo de suavização dentro do contêiner é o modo de suavização padrão. Você tem a liberdade de definir o modo de suavização do contêiner e os itens desenhados de dentro do contêiner serão desenhados de acordo com o modo é definido por você. Os itens sorteados após a chamada para serão sorteados de acordo com o modo de suavização (AntiAlias) que estava em vigor antes da chamada para .EndContainerBeginContainer

Várias camadas de contêineres aninhados

Você não está limitado a um contêiner em um Graphics objeto. É possível criar uma sequência de contêineres, cada um deles aninhado no anterior e é possível especificar a transformação global, a área de recorte e as configurações de qualidade de cada um desses contêineres aninhados. Se você chamar um método de desenho de dentro do contêiner mais interno, as transformações serão aplicadas em ordem, começando pelo contêiner mais interno e terminando com mais externo. Itens desenhados de dentro do contêiner mais interno serão recortados pela interseção de todas as áreas de recorte.

O exemplo a seguir cria um Graphics objeto e define sua dica de renderização de texto como AntiAlias. O código cria dois contêineres, um aninhado dentro do outro. A dica de renderização de texto do contêiner externo é definida como SingleBitPerPixel, e a dica de renderização de texto do contêiner interno é definida como AntiAlias. O código desenha três cadeias de caracteres: uma do contêiner interno, uma do contêiner externo e uma do Graphics próprio objeto.

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))

A ilustração a seguir mostra as três cadeias de caracteres. As cadeias de caracteres desenhadas do contêiner interno e do Graphics objeto são suavizadas pela suavização de serrilhado. A cadeia de caracteres desenhada do contêiner externo não é suavizada pela suavização de borda porque a TextRenderingHint propriedade é definida como SingleBitPerPixel.

Illustration that shows the strings drawn from nested containers.

Confira também