入れ子になっているグラフィックス コンテナの使用
更新 : 2007 年 11 月
GDI+ には、Graphics オブジェクトの状態の一部を一時的に置換または増加するために使用できるコンテナが用意されています。コンテナを作成するには、Graphics オブジェクトの BeginContainer メソッドを呼び出します。BeginContainer を繰り返し呼び出すことで、入れ子になったコンテナを形成できます。EndContainer に対する各呼び出しは、BeginContainer と対になっている必要があります。
入れ子になっているコンテナでの変換
Graphics オブジェクトを作成し、その Graphics オブジェクト内にコンテナを作成する例を次に示します。Graphics オブジェクトのワールド変換は、x 方向に 100 単位、y 方向に 80 単位の平行移動です。コンテナのワールド変換は、30°の回転です。このコードでは、 DrawRectangle(pen, -60, -30, 120, 60) の呼び出しが 2 回行われます。DrawRectangle の最初の呼び出しはコンテナの内側で行われます。つまり、この呼び出しは、BeginContainer が呼び出されてから EndContainer が呼び出されるまでの間に行われます。DrawRectangle の 2 回目の呼び出しは、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 オブジェクトのワールド変換 (平行移動) だけによって変換されます。これら 2 つの四角形を次の図に示します。
入れ子になっているコンテナでのクリッピング
入れ子になっているコンテナがクリッピング領域を処理するようすを次の例に示します。このコードは、Graphics オブジェクトを作成し、その Graphics オブジェクト内にコンテナを作成します。Graphics オブジェクトのクリッピング領域は四角形で、コンテナのクリッピング領域は楕円です。このコードは、DrawLine メソッドを 2 回呼び出します。DrawLine の最初の呼び出しはコンテナの内部で行われ、DrawLine の 2 回目の呼び出しはコンテナの外側で、EndContainer の呼び出しの後に行われます。最初の直線は、2 つのクリッピング領域の交差部分でクリップされます。2 番目の直線は、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);
クリップされた 2 つの直線を次の図に示します。
上の 2 つの例が示すように、変換およびクリッピング領域は入れ子になっているコンテナ内では累積されます。コンテナおよび Graphics オブジェクトのワールド変換を設定すると、コンテナの内側から描画された項目に対しては両方の変換が適用されます。この場合、最初にコンテナの変換が適用され、次に Graphics オブジェクトの変換が適用されます。コンテナおよび Graphics オブジェクトのクリッピング領域を設定すると、コンテナの内側から描画された項目は、2 つのクリッピング領域の交差部分でクリップされます。
入れ子になっているコンテナでの画質設定
入れ子になっているコンテナでの画質の設定 (SmoothingMode, TextRenderingHint など) は累積されず、コンテナの画質設定によって Graphics オブジェクトの画質設定が一時的に置き換えられます。コンテナを新規作成するときに、そのコンテナの画質設定は既定値に設定されます。たとえば、スムージング モードが AntiAlias の Graphics オブジェクトがあるとします。コンテナを作成する場合、そのコンテナ内のスムージング モードは既定のスムージング モードになります。コンテナのスムージング モードは自由に設定でき、そのコンテナの内側から描画される全項目は、設定されているモードに基づいて描画されます。EndContainer を呼び出した後で描画される項目は、BeginContainer を呼び出す前に有効だったスムージング モード (AntiAlias) に基づいて描画されます。
入れ子になっている複数層のコンテナ
1 つの Graphics オブジェクト内に作成できるコンテナ数は 1 つに限定されているわけではありません。各コンテナが前のコンテナの入れ子になっている一連のコンテナを作成でき、入れ子になっているコンテナごとにワールド変換、クリッピング領域、および画質設定を指定できます。最も内側のコンテナから描画メソッドを呼び出す場合は、最も内側のコンテナから始まり最も外側のコンテナで終了するという順序で、変換が適用されます。最も内側のコンテナの内側から描画された項目は、すべてのクリッピング領域の交差部分でクリップされます。
Graphics オブジェクトを作成し、そのテキストの画質を指定する属性として AntiAlias を設定する例を次に示します。このコードは、1 つのコンテナがもう 1 つのコンテナ内に入れ子になっている 2 つのコンテナを作成します。外側のコンテナのテキストの画質を指定する属性は SingleBitPerPixel に、内側のコンテナのテキストの画質を指定する属性は AntiAlias に設定されます。このコードは、3 つの文字列を描画します。1 つは内側のコンテナからの文字列、1 つは外側のコンテナからの文字列、もう 1 つは 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));
これらの 3 つの文字列を次の図に示します。内側のコンテナおよび Graphics オブジェクトから描画された文字列は、アンチエイリアシングによって滑らかになっています。外側のコンテナから描画された文字列はアンチエイリアシングによって滑らかになってはいません。これは、TextRenderingHint プロパティが SingleBitPerPixel に設定されているためです。