Contenedores de gráficos anidados
GDI+ proporciona contenedores que pueden utilizarse para reemplazar o aumentar temporalmente parte del estado de un objeto Graphics. Para crear un contenedor nuevo, hay que llamar al método BeginContainer de un objeto Graphics. Se puede llamar a BeginContainer varias veces para formar contenedores anidados. Cada llamada a BeginContainer debe emparejarse con una llamada a EndContainer.
Transformaciones de los contenedores anidados
En el siguiente ejemplo se crea un objeto Graphics y un contenedor dentro de dicho objeto. La transformación universal del objeto Graphics es una conversión de 100 unidades en la dirección del eje x y de 80 unidades en la dirección del eje y. La transformación universal del contenedor es una rotación de 30 grados. El código realiza la llamada DrawRectangle(pen, -60, -30, 120, 60)
dos veces. La primera llamada a DrawRectangle se realiza dentro del contenedor; es decir, entre las llamadas a BeginContainer y a EndContainer. La segunda llamada a DrawRectangle se produce después de la llamada a EndContainer.
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)
[C#]
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);
En el fragmento de código anterior, el rectángulo dibujado desde dentro del contenedor es transformado primero por la transformación universal del contenedor (rotación) y luego por la transformación universal del objeto Graphics (conversión). El rectángulo dibujado desde fuera del contenedor sólo es transformado por la transformación universal del objeto Graphics (conversión). En la siguiente ilustración se muestran los dos rectángulos.
Recortar en los contenedores anidados
En el siguiente ejemplo se muestra cómo los contenedores anidados controlan las regiones de recorte. El código crea un objeto Graphics y un contenedor dentro de dicho objeto. La región de recorte del objeto Graphics es un rectángulo, mientras que la región del contenedor es una elipse. El código hace dos llamadas al método DrawLine. La primera llamada a DrawLine de realiza dentro del contenedor, y la segunda, fuera de éste (a continuación de la llamada a EndContainer). La primera línea se recorta por la intersección de las dos regiones de recorte. La segunda línea se recorta únicamente por la región de recorte rectangular del objeto Graphics.
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)
[C#]
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);
En la siguiente ilustración se muestran las dos líneas recortadas.
Cómo se indica en los dos ejemplos anteriores, las transformaciones y las regiones de recorte son acumulativas en los contenedores anidados. Si se establecen las transformaciones universales del contenedor y del objeto Graphics, ambas se aplicarán a los elementos dibujados desde dentro del contenedor. Primero se aplicará la transformación del contenedor, seguida de la transformación del objeto Graphics. Si se establecen las regiones de recorte del contenedor y del objeto Graphics, los elementos que se dibujen desde dentro del contenedor serán recortados por la intersección de las dos regiones de recorte.
Valores de calidad de los contenedores anidados
Los valores de calidad (SmoothingMode, TextRenderingHint y similares) de los contenedores anidados no son acumulativos, sino que reemplazan de forma temporal a los valores de calidad de un objeto Graphics. Cuando se crea un contenedor nuevo, los valores de calidad de dicho contenedor se establecen en sus parámetros predeterminados. Por ejemplo, supongamos que un objeto Graphics tiene un modo de suavizado AntiAlias. Cuando se crea un contenedor, el modo de suavizado dentro del contenedor es el modo de suavizado predeterminado. El modo de suavizado del contenedor se puede elegir libremente, y los elementos que se dibujen desde dentro del contenedor se ajustarán al modo establecido. Los elementos dibujados después de la llamada a EndContainer se dibujarán según el modo de suavizado (AntiAlias) establecido antes la llamada a BeginContainer.
Varias capas de contenedores anidados
Los objetos Graphics no se limitan a un solo contenedor. Se puede crear una secuencia de contenedores, cada uno anidado en el anterior, y especificar la transformación universal, la región de recorte y los valores de calidad de cada uno de estos contenedores anidados. Si la llamada a un método de dibujo se realiza desde dentro del contenedor más interno, las transformaciones se aplicarán en orden, desde el contenedor más interno hasta el más externo. Los elementos dibujados desde dentro del contenedor más interno serán recortados por la intersección de todas las regiones de recorte.
En el ejemplo siguiente se crea un objeto Graphics y se establece la indicación de procesamiento de texto en AntiAlias. El código crea dos contenedores, uno anidado dentro del otro. La indicación de procesamiento de texto del contenedor exterior se establece en SingleBitPerPixel, y la del contenedor interior, en AntiAlias. El código dibuja tres cadenas: una desde el contenedor interior, otra desde el contenedor exterior y otra desde el propio objeto Graphics.
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 = TextRenderingHint.AntiAlias
outerContainer = graphics.BeginContainer()
graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixel
innerContainer = graphics.BeginContainer()
graphics.TextRenderingHint = 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))
[C#]
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 = TextRenderingHint.AntiAlias;
outerContainer = graphics.BeginContainer();
graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixel;
innerContainer = graphics.BeginContainer();
graphics.TextRenderingHint = 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));
En la siguiente ilustración se muestran las tres cadenas. Las cadenas dibujadas desde el contenedor interior y desde el objeto Graphics se suavizan mediante el alisado. La cadena dibujada desde el contendor exterior no se suaviza mediante alisado porque la propiedad TextRenderingHint está establecida en SingleBitPerPixel.