Поделиться через


Использование вложенных графических контейнеров

GDI+ предоставляет контейнеры, которые можно использовать для временной замены или расширения части состояния в объекте Graphics. Контейнер создается путем вызова метода BeginContainer объекта Graphics. Вы можете повторно вызывать BeginContainer для создания вложенных контейнеров. Каждый вызов BeginContainer должен быть связан с вызовом EndContainer.

Преобразования в вложенных контейнерах

В следующем примере создается объект Graphics и контейнер в этом объекте Graphics. Преобразование мира объекта Graphics — это перевод 100 единиц в направлении x и 80 единиц в направлении y. Глобальное преобразование контейнера — это поворот на 30 градусов. Код выполняет вызов DrawRectangle(pen, -60, -30, 120, 60) дважды. Первый вызов DrawRectangle находится внутри контейнера; То есть вызов находится между вызовами BeginContainer и EndContainer. Второй вызов на DrawRectangle происходит после вызова на 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)

В приведенном выше коде прямоугольник, нарисованный внутри контейнера, сначала преобразуется мировым преобразованием контейнера (вращение), а затем мировым преобразованием объекта Graphics (сдвиг). Прямоугольник, нарисованный извне контейнера, преобразуется только путем преобразования мира объекта Graphics (перевода). На следующем рисунке показаны два прямоугольника:

иллюстрация, представляющая вложенные контейнеры.

Вырезка в вложенных контейнерах

В следующем примере показано, как вложенные контейнеры обрабатывают области отсечения. Код создает объект Graphics и контейнер в этом объекте Graphics. Область вырезки объекта Graphics представляет собой прямоугольник, а область вырезки контейнера — многоточие. Код выполняет два вызова метода DrawLine. Первый вызов DrawLine находится внутри контейнера, а второй вызов DrawLine находится за пределами контейнера (после вызова EndContainer). Первая строка обрезается пересечением двух областей обрезки. Вторая строка обрезается только прямоугольной областью обрезки объекта 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)

На следующем рисунке показаны две обрезанные строки:

иллюстрация, показывающая вложенный контейнер с обрезанными строками.

Как показано в двух предыдущих примерах, преобразования и обрезки регионов являются совокупными в вложенных контейнерах. Если вы задали мир преобразований контейнера и объекта Graphics, оба преобразования будут применяться к элементам, полученным из контейнера. Преобразование контейнера будет применено первым, а преобразование объекта Graphics будет применено второе. Если задать области вырезки контейнера и объекта Graphics, элементы, полученные изнутри контейнера, будут обрезаться пересечением двух областей обрезки.

Параметры качества в вложенных контейнерах

Параметры качества (SmoothingMode, TextRenderingHintи подобные) в вложенных контейнерах не являются накопительными; вместо этого параметры качества контейнера временно заменяют параметры качества объекта Graphics. При создании нового контейнера параметры качества для этого контейнера задаются значениями по умолчанию. Например, предположим, что у вас есть объект Graphics с режимом сглаживания AntiAlias. При создании контейнера режим сглаживания внутри контейнера является режимом сглаживания по умолчанию. Вы можете задать режим сглаживания контейнера, а все элементы, нарисованные изнутри контейнера, будут вырисовываться в соответствии с заданным режимом. Элементы, рисуемые после вызова EndContainer, будут вырисовываться в соответствии с режимом сглаживания (AntiAlias), который был на месте перед вызовом BeginContainer.

Несколько слоев вложенных контейнеров

Вы не ограничиваетесь одним контейнером в объекте Graphics. Можно создать последовательность контейнеров, где каждый вложен в предыдущий, и задать параметры мирового преобразования, области обрезки и качества для каждого из этих вложенных контейнеров. При вызове метода рисования из самого внутреннего контейнера преобразования будут применены в порядке, начиная с самого внутреннего контейнера и заканчивая самым внешним контейнером. Элементы, нарисованные изнутри самого внутреннего контейнера, будут обрезаны на пересечении всех областей вырезки.

В следующем примере создается объект Graphics и устанавливает параметр отрисовки текста на AntiAlias. Код создает два контейнера, вложенные в другое. Указание отрисовки текста внешнего контейнера имеет значение SingleBitPerPixel, а указание отрисовки текста внутреннего контейнера имеет значение AntiAlias. Код рисует три строки: одну из внутреннего контейнера, одну из внешнего контейнера и одну из самого объекта 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))

На следующем рисунке показаны три строки. Строки, полученные из внутреннего контейнера и из объекта Graphics, сглаживаются путем защиты. Строка, полученная из внешнего контейнера, не сглаживается путем защиты, так как свойство TextRenderingHint имеет значение SingleBitPerPixel.

Иллюстрация, которая показывает строки, извлеченные из вложенных контейнеров.

См. также