Графические контейнеры
Состояние графики — область вырезки, преобразования и параметры качества — хранится в объекте графических. Windows GDI+ позволяет временно заменить или расширить часть состояния в объекте графических с помощью контейнера. Контейнер запускается путем вызова метода Graphics::BeginContainer объекта графики и завершения контейнера путем вызова метода Graphics::EndContainer. Между Графикой::BeginContainer и Graphics::EndContainer, любые изменения состояния, внесенные в объект графики, принадлежат контейнеру и не перезаписывают существующее состояние объекта графики.
В следующем примере создается контейнер в объекте Graphics. Преобразование графических — это перевод 200 единиц справа, а преобразование контейнера — это перевод 100 единиц вниз.
myGraphics.TranslateTransform(200.0f, 0.0f);
myGraphicsContainer = myGraphics.BeginContainer();
myGraphics.TranslateTransform(0.0f, 100.0f);
myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50);
myGraphics.EndContainer(myGraphicsContainer);
myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50);
Обратите внимание, что в предыдущем примере оператор myGraphics.DrawRectangle(&myPen, 0, 0, 50, 50)
, сделанный между вызовами Graphics::BeginContainer и Graphics::EndContainer создает другой прямоугольник, чем тот же оператор, сделанный после вызова Graphics::EndContainer. Только горизонтальное преобразование применяется к вызову DrawRectangle, сделанному за пределами контейнера. Оба преобразования — горизонтальное преобразование 200 единиц и вертикальное преобразование 100 единиц — применяются к вызову Graphics::D rawRectangle вызов в контейнере. На следующем рисунке показаны два прямоугольника.
Контейнеры можно вложить в контейнеры. В следующем примере создается контейнер в объекте graphics и другом контейнере в первом контейнере. Преобразование мира объекта графики — это преобразование 100 единиц в направлении x и 80 единиц в направлении y. Преобразование мира первого контейнера — это поворот в 30 градусов. Преобразование второго контейнера — это масштабирование на 2 в направлении x. Вызов метода Graphics::D rawEllipse выполняется внутри второго контейнера.
myGraphics.TranslateTransform(100.0f, 80.0f, MatrixOrderAppend);
container1 = myGraphics.BeginContainer();
myGraphics.RotateTransform(30.0f, MatrixOrderAppend);
container2 = myGraphics.BeginContainer();
myGraphics.ScaleTransform(2.0f, 1.0f);
myGraphics.DrawEllipse(&myPen, -30, -20, 60, 40);
myGraphics.EndContainer(container2);
myGraphics.EndContainer(container1);
На следующем рисунке показан многоточие.
Обратите внимание, что все три преобразования применяются к вызову Graphics::D rawEllipse, выполненным во втором (внутреннем) контейнере. Кроме того, обратите внимание на порядок преобразований: сначала масштаб, а затем поворот, а затем перевод. Самое внутреннее преобразование применяется сначала, и самое внешнее преобразование применяется последнее.
Любое свойство объектаграфикиможно задать внутри контейнера (между вызовами Graphics::BeginContainer и Graphics::EndContainer). Например, область вырезки может быть задана внутри контейнера. Любой документ, выполненный внутри контейнера, будет ограничен областью вырезки этого контейнера, а также будет ограничен областями вырезки любых внешних контейнеров и областью вырезки графических самого объекта.
Свойства, рассмотренные до сих пор , — преобразование мира и регион вырезки — объединяются вложенными контейнерами. Другие свойства временно заменяются вложенным контейнером. Например, если в контейнере задан режим сглаживания SmoothingModeAntiAlias, все методы рисования, вызываемые внутри этого контейнера, будут использовать режим сглаживания антиалиасов, но методы рисования, называемые после Graphics::EndContainer, будут использовать режим сглаживания, который был установлен перед вызовом Graphics::BeginContainer.
Для другого примера объединения преобразований мира объекта графики и контейнера предположим, что вы хотите нарисовать глаз и поместить его в различные места в последовательности лиц. В следующем примере показано, как вывести глаз в центр источника системы координат.
void DrawEye(Graphics* pGraphics)
{
GraphicsContainer eyeContainer;
eyeContainer = pGraphics->BeginContainer();
Pen myBlackPen(Color(255, 0, 0, 0));
SolidBrush myGreenBrush(Color(255, 0, 128, 0));
SolidBrush myBlackBrush(Color(255, 0, 0, 0));
GraphicsPath myTopPath;
myTopPath.AddEllipse(-30, -50, 60, 60);
GraphicsPath myBottomPath;
myBottomPath.AddEllipse(-30, -10, 60, 60);
Region myTopRegion(&myTopPath);
Region myBottomRegion(&myBottomPath);
// Draw the outline of the eye.
// The outline of the eye consists of two ellipses.
// The top ellipse is clipped by the bottom ellipse, and
// the bottom ellipse is clipped by the top ellipse.
pGraphics->SetClip(&myTopRegion);
pGraphics->DrawPath(&myBlackPen, &myBottomPath);
pGraphics->SetClip(&myBottomRegion);
pGraphics->DrawPath(&myBlackPen, &myTopPath);
// Fill the iris.
// The iris is clipped by the bottom ellipse.
pGraphics->FillEllipse(&myGreenBrush, -10, -15, 20, 22);
// Fill the pupil.
pGraphics->FillEllipse(&myBlackBrush, -3, -7, 6, 9);
pGraphics->EndContainer(eyeContainer);
}
На следующем рисунке показан глаз и оси координат.
Функция DrawEye, определенная в предыдущем примере, получает адрес объекта graphics и немедленно создает контейнер в этом объекте graphics. Этот контейнер изолирует любой код, вызывающий функцию DrawEye от параметров свойств, сделанных во время выполнения функции DrawEye. Например, код в функции DrawEye задает область вырезки объекта графики, но когда DrawEye возвращает элемент управления в вызывающую подпрограмму, область вырезки будет так же, как и перед вызовом DrawEye.
Следующий пример рисует три многоточия (лица), каждый из которых находится внутри глаза.
// Draw an ellipse with center at (100, 100).
myGraphics.TranslateTransform(100.0f, 100.0f);
myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);
// Draw the eye at the center of the ellipse.
DrawEye(&myGraphics);
// Draw an ellipse with center at 200, 100.
myGraphics.TranslateTransform(100.0f, 0.0f, MatrixOrderAppend);
myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);
// Rotate the eye 40 degrees, and draw it 30 units above
// the center of the ellipse.
myGraphicsContainer = myGraphics.BeginContainer();
myGraphics.RotateTransform(-40.0f);
myGraphics.TranslateTransform(0.0f, -30.0f, MatrixOrderAppend);
DrawEye(&myGraphics);
myGraphics.EndContainer(myGraphicsContainer);
// Draw a ellipse with center at (300.0f, 100.0f).
myGraphics.TranslateTransform(100.0f, 0.0f, MatrixOrderAppend);
myGraphics.DrawEllipse(&myBlackPen, -40, -60, 80, 120);
// Stretch and rotate the eye, and draw it at the
// center of the ellipse.
myGraphicsContainer = myGraphics.BeginContainer();
myGraphics.ScaleTransform(2.0f, 1.5f);
myGraphics.RotateTransform(45.0f, MatrixOrderAppend);
DrawEye(&myGraphics);
myGraphics.EndContainer(myGraphicsContainer);
На следующем рисунке показаны три многоточия.
В предыдущем примере все многоточия рисуются с помощью вызова DrawEllipse(&myBlackPen, -40, -60, 80, 120)
, который рисует многоточие в центре источника системы координат. Многоточие перемещается от левого верхнего угла клиентской области, задав преобразование мира объекта графики. Оператор приводит к тому, что первый многоточие будет сосредоточено на (100, 100). Оператор приводит к тому, что центр второго многоточия будет 100 единиц справа от центра первого многоточия. Аналогичным образом, центр третьего многоточия составляет 100 единиц справа от центра второго многоточия.
Контейнеры в предыдущем примере используются для преобразования глаза относительно центра заданного многоточия. Первый глаз рисуется в центре многоточия без преобразования, поэтому вызов DrawEye не находится внутри контейнера. Второй глаз поворачивается на 40 градусов и рисуется 30 единиц над центром многоточия, поэтому функция DrawEye и методы, устанавливающие преобразование, вызываются внутри контейнера. Третий глаз растягивается и поворачивается и рисуется в центре эллипса. Как и во втором глазе, функция DrawEye и методы, которые задают преобразование, вызываются внутри контейнера.