중첩된 Graphics 컨테이너 사용
GDI+에서는 Graphics 개체에서 상태의 일부를 임시로 교체하거나 확대하는 데 사용할 수 있는 컨테이너를 제공합니다. 컨테이너를 만들 경우에는 Graphics 개체의 BeginContainer 메서드를 호출합니다. BeginContainer를 반복적으로 호출하여 중첩 컨테이너를 만들 수 있습니다. BeginContainer를 한 번 호출할 때마다 EndContainer도 한 번씩 호출해야 합니다.
중첩 컨테이너에서 변환
다음 예제에서는 Graphics 개체와 이 Graphics 개체 안에 컨테이너를 만듭니다. Graphics 개체에 대한 전역 변환에서는 x 방향으로 100단위 이동하고 y 방향으로 80단위 이동합니다. 컨테이너에 대한 전역 변환에서는 30도 회전합니다. 이 코드에서는 DrawRectangle(pen, -60, -30, 120, 60) 을 두 번 호출합니다. 첫 번째 DrawRectangle 호출은 컨테이너 안에서 수행됩니다. 즉, BeginContainer를 호출한 후 EndContainer를 호출하기 전에 수행됩니다. 두 번째 DrawRectangle 호출은 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)
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);
위의 코드에서 컨테이너 안에서 그린 사각형은 먼저 컨테이너의 전역 변환을 통해 변환된 다음(회전) Graphics 개체의 전역 변환을 통해 변환되고(이동) 컨테이너 밖에서 그린 사각형은 Graphics 개체의 전역 변환을 통해서만 변환됩니다(이동). 아래 그림에 이러한 두 개의 사각형이 나와 있습니다.
중첩 컨테이너에서 클리핑
아래 예제에서는 중첩된 컨테이너에서 클리핑 영역을 처리하는 방법을 보여 줍니다. 이 코드에서는 Graphics 개체와 이 Graphics 개체 안에 컨테이너를 만듭니다. Graphics 개체의 클리핑 영역은 사각형이며 컨테이너의 클리핑 영역은 타원입니다. 이 코드에서는 DrawLine 메서드를 두 번 호출합니다. 첫 번째 DrawLine 호출은 컨테이너 안에서 수행되고 두 번째 DrawLine 호출은 EndContainer를 호출한 후 컨테이너 외부에서 수행됩니다. 첫 번째 선은 두 클리핑 영역의 교차 부분에 의해 클리핑됩니다. 두 번째 선은 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)
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);
아래 그림에 클리핑된 두 개의 선이 나와 있습니다.
위의 두 예제에서 보았듯이 중첩된 컨테이너에서 변환과 클리핑 영역은 누진적으로 적용됩니다. 컨테이너와 Graphics 개체에 대해 둘 다 전역 변환을 설정하면 컨테이너 안에서 그리는 항목에 두 변환이 모두 적용됩니다. 이 때 컨테이너의 변환이 먼저 적용되고 Graphics 개체의 변환이 두 번째로 적용됩니다. 컨테이너와 Graphics 개체에 대해 둘 다 클리핑 영역을 설정하면 컨테이너 안에서 그리는 항목이 두 클리핑 영역의 교차 부분에 의해 클리핑됩니다.
중첩 컨테이너에서 품질 설정
중첩 컨테이너에서 SmoothingMode, TextRenderingHint와 같은 품질 설정은 누적되지 않고 Graphics 개체의 품질 설정 대신 컨테이너의 품질 설정이 임시로 사용됩니다. 새로 만드는 컨테이너의 품질 설정은 기본값으로 지정됩니다. 예를 들어 다듬기 모드가 AntiAlias인 Graphics 개체가 있다고 가정합니다. 컨테이너를 만들 때 컨테이너 안의 다듬기 모드는 기본 다듬기 모드로 설정되지만, 필요하면 이를 다르게 설정하여 컨테이너 안에서 그리는 항목에 적용되도록 할 수 있습니다. 그러나 EndContainer를 호출한 후 그리는 항목에는 BeginContainer를 호출하기 전에 설정되어 있던 다듬기 모드(AntiAlias)가 적용됩니다.
중첩된 컨테이너의 여러 계층
Graphics 개체에 여러 개의 컨테이너를 둘 수 있습니다. 연이어 중첩되는 일련의 컨테이너를 만들고 중첩된 컨테이너 각각에 대해 전역 변환, 클리핑 영역 및 품질 설정을 지정할 수 있습니다. 가장 안쪽의 컨테이너에서 그리기 메서드를 호출하면 가장 안쪽 컨테이너에서 시작하여 가장 바깥쪽 컨테이너까지 순서대로 변환이 적용됩니다. 가장 안쪽 컨테이너에서 그리는 항목은 모든 클리핑 영역의 교차 부분에 의해 클리핑됩니다.
다음 예제에서는 Graphics 개체를 만들고 텍스트 렌더링 힌트를 AntiAlias로 설정합니다. 이 코드에서는 한 컨테이너가 다른 컨테이너에 중첩된 방식으로 두 개의 컨테이너를 만듭니다. 이 때 외부 컨테이너의 텍스트 렌더링 힌트는 SingleBitPerPixel로 설정하고 내부 컨테이너의 텍스트 렌더링 힌트는 AntiAlias로 설정합니다. 이 코드에서는 내부 컨테이너, 외부 컨테이너, 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 = _
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 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));
아래 그림에 세 개의 문자열이 나와 있습니다. 내부 컨테이너 및 Graphics 개체에서 그리는 문자열은 앤티 앨리어싱을 통해 다듬어집니다. 그러나 외부 컨테이너에서 그리는 문자열의 경우 TextRenderingHint 속성이 SingleBitPerPixel로 설정되어 있으므로 앤티 앨리어싱을 통해 다듬어지지 않습니다.