Partilhar via


Usando contêineres gráficos aninhados

GDI+ fornece contêineres que você pode usar para substituir temporariamente ou aumentar 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 BeginContainer deve ser emparelhada com uma chamada para EndContainer.

Transformações em contêineres aninhados

O exemplo a seguir cria um Graphics objeto e um contêiner dentro desse Graphics objeto. A transformação mundial do objeto Graphics é uma translação de 100 unidades em relação ao eixo x e 80 unidades em relação ao eixo y. A transformação mundial do contentor é uma rotação de 30 graus. O código faz a chamada DrawRectangle(pen, -60, -30, 120, 60) duas vezes. A primeira chamada para DrawRectangle está dentro do contêiner, ou seja, a chamada está entre as chamadas para BeginContainer e EndContainer. A segunda chamada para DrawRectangle é após a chamada para 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)

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

Ilustração que mostra contêineres aninhados.

Clipping em contêineres aninhados

O exemplo a seguir demonstra como os contêineres aninhados lidam com regiões de recorte. O código cria um Graphics objeto e um contêiner dentro desse Graphics objeto. A região de recorte do Graphics objeto é um retângulo e a região de recorte do contêiner é uma elipse. O código faz duas chamadas para o DrawLine método. A primeira chamada para DrawLine está dentro do contêiner e a segunda chamada para DrawLine está fora do contêiner (após a chamada para EndContainer). A primeira linha é cortada pela intersecção das duas regiões de recorte. A segunda linha é cortada apenas pela região de recorte retangular do objeto 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)

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

Ilustração que mostra um contentor aninhado com linhas recortadas.

Como mostram os dois exemplos anteriores, as transformações e as regiões 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 aos itens extraídos 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 lugar. Se você definir as regiões de recorte do contêiner e do objeto, os Graphics itens extraídos 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, TextRenderingHint, e similares) em contêineres aninhados não são cumulativas, em vez disso, as 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 para esse contêiner são definidas como valores padrão. Por exemplo, suponha que você tenha um Graphics objeto com um 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ê é livre para definir o modo de suavização do recipiente, e quaisquer itens retirados de dentro do recipiente serão desenhados de acordo com o modo que você definir. Os itens sorteados após a chamada para EndContainer serão sorteados de acordo com o modo de suavização (AntiAlias) que estava em vigor antes da chamada para BeginContainer.

Várias camadas de contêineres aninhados

Você não está limitado a um contêiner em um Graphics objeto. Você pode criar uma sequência de contêineres, cada um aninhado no anterior, e pode especificar a transformação mundial, a região 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 com o contêiner mais interno e terminando com o contêiner mais externo. Os itens retirados de dentro do recipiente mais interno serão cortados pela interseção de todas as regiões 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 no 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. Os cordéis extraídos do contenedor interno e do objeto Graphics são suavizados pela suavização de bordas. A string extraída da caixa externa não é suavizada pelo antialiasing porque a propriedade TextRenderingHint está definida para SingleBitPerPixel.

Ilustração que mostra as cadeias de caracteres extraídas de contêineres aninhados.

Ver também