Udostępnij za pośrednictwem


Używanie zagnieżdżonych kontenerów grafiki

GDI+ udostępnia kontenery, których można użyć do tymczasowego zastąpienia lub rozszerzenia części stanu w obiekcie Graphics. Kontener jest tworzony przez wywołanie metody BeginContainer obiektu Graphics. Możesz wielokrotnie wywoływać BeginContainer, aby tworzyć zagnieżdżone kontenery. Każde wywołanie BeginContainer musi być sparowane z wywołaniem EndContainer.

Przekształcenia w zagnieżdżonych kontenerach

Poniższy przykład tworzy obiekt Graphics i kontener w tym obiekcie Graphics. Światowa transformacja obiektu Graphics to przesunięcie o 100 jednostek w kierunku x i 80 jednostek w kierunku y. Światowa transformacja kontenera jest rotacją 30 stopni. Kod wykonuje wywołanie DrawRectangle(pen, -60, -30, 120, 60) dwa razy. Pierwsze wywołanie DrawRectangle znajduje się wewnątrz kontenera; oznacza to, że wywołanie znajduje się między wywołaniami BeginContainer i EndContainer. Drugie wywołanie DrawRectangle następuje po wywołaniu 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)

W poprzednim kodzie prostokąt narysowany wewnątrz kontenera jest najpierw przekształcany przez transformację świata kontenera (rotację), a następnie przez światową transformację obiektu Graphics (tłumaczenie). Prostokąt narysowany spoza kontenera jest przekształcany tylko przez transformację świata obiektu Graphics (tłumaczenie). Poniższa ilustracja przedstawia dwa prostokąty:

Ilustracja przedstawiająca zagnieżdżone kontenery.

Przycinanie w zagnieżdżonych kontenerach

W poniższym przykładzie pokazano, jak zagnieżdżone kontenery obsługują obszary przycinania. Kod tworzy obiekt Graphics i kontener w tym obiekcie Graphics. Obszar przycinania obiektu Graphics jest prostokątem, a obszar przycinania kontenera to elipsa. Kod wykonuje dwa wywołania metody DrawLine. Pierwsze wywołanie DrawLine znajduje się wewnątrz kontenera, a drugie wywołanie DrawLine znajduje się poza kontenerem (po wywołaniu EndContainer). Pierwszy wiersz jest przycięty przez przecięcie się dwóch obszarów przycinania. Drugi wiersz jest przycinany tylko przez prostokątny obszar przycinania obiektu 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)

Poniższa ilustracja przedstawia dwie przycięte linie:

Ilustracja przedstawiająca zagnieżdżony kontener ze obciętymi liniami.

Jak pokazano w dwóch poprzednich przykładach, przekształcenia i obszary przycinania się kumulują w zagnieżdżonych kontenerach. Jeśli ustawisz przekształcenia świata kontenera i obiekt Graphics, oba przekształcenia zostaną zastosowane do elementów pochodzących z wewnątrz kontenera. Najpierw zostanie zastosowana transformacja kontenera, a przekształcenie obiektu Graphics zostanie zastosowane w drugiej kolejności. Jeśli ustawisz regiony przycinania kontenera i obiekt Graphics, elementy pobierane z wewnątrz kontenera zostaną ograniczone przez przecięcie dwóch regionów przycinania.

Ustawienia jakości w zagnieżdżonych kontenerach

Ustawienia jakości (SmoothingMode, TextRenderingHinti podobne) w kontenerach zagnieżdżonych nie są skumulowane; zamiast tego ustawienia jakości kontenera tymczasowo zastępują ustawienia jakości obiektu Graphics. Podczas tworzenia nowego kontenera ustawienia jakości dla tego kontenera są ustawione na wartości domyślne. Załóżmy na przykład, że masz obiekt Graphics z trybem wygładzania AntiAlias. Podczas tworzenia kontenera tryb wygładzania wewnątrz kontenera jest domyślnym trybem wygładzania. Możesz ustawić tryb wygładzania kontenera, a wszystkie elementy pobierane z wewnątrz kontenera będą rysowane zgodnie z ustawionym trybem. Elementy rysowane po wywołaniu EndContainer zostaną narysowane zgodnie z trybem wygładzania (AntiAlias), który obowiązywał przed wywołaniem BeginContainer.

Kilka warstw zagnieżdżonych kontenerów

Nie ograniczasz się do jednego kontenera w obiekcie Graphics. Możesz utworzyć sekwencję kontenerów, z których każdy jest zagnieżdżony w poprzednim, i możesz określić transformację świata, region wycinania oraz ustawienia jakości każdego z tych zagnieżdżonych kontenerów. Jeśli wywołasz metodę rysunku z wewnątrz najbardziej wewnętrznego kontenera, przekształcenia zostaną zastosowane w kolejności, począwszy od najbardziej wewnętrznego kontenera i kończąc na najbardziej zewnętrznym kontenerze. Elementy pobierane z wnętrza najbardziej wewnętrznego kontenera zostaną obcięte przez przecięcie wszystkich regionów wycinków.

Poniższy przykład tworzy obiekt Graphics i ustawia jego wskazówkę renderowania tekstu na AntiAlias. Kod tworzy dwa kontenery, jeden zagnieżdżony w drugiej. Wskazówka renderowania tekstu zewnętrznego kontenera jest ustawiona na SingleBitPerPixel, a wskazówka renderowania tekstu kontenera wewnętrznego jest ustawiona na wartość AntiAlias. Kod rysuje trzy ciągi: jeden z kontenera wewnętrznego, jeden z kontenera zewnętrznego i jeden z samego obiektu Graphics.

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))

Na poniższej ilustracji przedstawiono trzy ciągi. Ciągi pobierane z kontenera wewnętrznego i z obiektu Graphics są wygładzone za pomocą antyaliasingu. Tekst pobrany z kontenera zewnętrznego nie jest wygładzony przez antyaliasing, ponieważ właściwość TextRenderingHint została ustawiona na SingleBitPerPixel.

Ilustracja przedstawiająca ciągi pobierane z zagnieżdżonych kontenerów.

Zobacz też