使用巢狀圖形容器
更新:2007 年 11 月
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。