Изменения в модели программирования
В следующих разделах описано несколько способов программирования с помощью Windows GDI+ отличается от программирования с помощью интерфейса графического устройства Windows (GDI).
- Контексты устройств, дескрипторы и графические объекты
- Два способа рисования линии
- Ручки, кисти, пути, изображения и шрифты в качестве параметров
- Перегрузка метода
- Больше нет текущей позиции
- Отдельные методы для рисования и заливки
- Создание регионов
Контексты устройств, дескрипторы и графические объекты
Если вы написали программы с помощью GDI (интерфейс графического устройства, включенный в предыдущие версии Windows), вы знакомы с идеей контекста устройства (DC). Контекст устройства — это структура, используемая Windows для хранения сведений о возможностях конкретного устройства отображения и атрибутов, которые определяют способ рисования элементов на этом устройстве. Контекст устройства для отображения видео также связан с определенным окном на экране. Сначала вы получите дескриптор контекста устройства (HDC), а затем передайте этот дескриптор в качестве аргумента в функции GDI, которые фактически выполняют рисование. Вы также передаете дескриптор в качестве аргумента в функции GDI, которые получают или задают атрибуты контекста устройства.
При использовании GDI+, при использовании GDI вам не нужно беспокоиться о дескрипторах и контекстах устройств, как и при использовании GDI. Вы просто создаете графический объект, а затем вызываете его методы в знакомом объектно-ориентированном стиле — myGraphicsObject.DrawLine(parameters). Графический объект находится в основе GDI+ так же, как контекст устройства находится в основе GDI. Контекст устройства и графический объект играют аналогичные роли, но существуют некоторые фундаментальные различия между моделью программирования на основе дескрипторов, используемой с контекстами устройств (GDI) и объектно-ориентированной моделью, используемой с графическими объектами (GDI+).
Графический объект, например контекст устройства, связан с определенным окном на экране и содержит атрибуты (например, режим сглаживания и подсказка отрисовки текста), указывающие способ рисования элементов. Однако графический объект не привязан к перу, кисти, пути, изображения или шрифта в качестве контекста устройства. Например, в GDI перед использованием контекста устройства для рисования линии необходимо вызвать SelectObject , чтобы связать объект пера с контекстом устройства. Это называется выбором пера в контексте устройства. Все линии, рисуемые в контексте устройства, будут использовать это перо, пока не выберете другое перо. При использовании GDI+вы передаете объект Pen в качестве аргумента методу DrawLine класса Graphics. Вы можете использовать другой объект Pen в каждом из ряда вызовов DrawLine, не связав заданный объект Pen с графическим объектом.
Два способа рисования линии
В следующих двух примерах каждая рисует красную линию ширины 3 из расположения (20, 10) в расположение (200 100). Первый пример вызывает GDI, а второй вызывает GDI+ через интерфейс класса C++.
Рисование линии с помощью GDI
Чтобы нарисовать линию с GDI, вам потребуется два объекта: контекст устройства и перо. Вы получите дескриптор контекста устройства, вызвав BeginPaint и дескриптор пера, вызвав CreatePen. Затем вызовите SelectObject , чтобы выбрать перо в контексте устройства. Вы устанавливаете положение пера (20, 10), вызывая MoveToEx , а затем рисуя линию из этой позиции пера (200, 100), вызывая LineTo. Обратите внимание, что MoveToEx и LineTo получают hdc в качестве аргумента.
HDC hdc;
PAINTSTRUCT ps;
HPEN hPen;
HPEN hPenOld;
hdc = BeginPaint(hWnd, &ps);
hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
hPenOld = (HPEN)SelectObject(hdc, hPen);
MoveToEx(hdc, 20, 10, NULL);
LineTo(hdc, 200, 100);
SelectObject(hdc, hPenOld);
DeleteObject(hPen);
EndPaint(hWnd, &ps);
Рисование строки с помощью GDI+ и интерфейса класса C++
Чтобы нарисовать линию с помощью GDI+ и интерфейса класса C++, вам потребуется объект Graphics и объект Pen. Обратите внимание, что windows не запрашивает дескриптор для этих объектов. Вместо этого конструкторы используются для создания экземпляра класса Графики (объекта графики) и экземпляра класса Pen (объект Pen). Рисование линии включает вызов метода Graphics::D rawLine класса Graphics. Первый параметр метода Graphics::D rawLine — это указатель на объект Pen. Это более простая и более гибкая схема, чем выбор пера в контексте устройства, как показано в предыдущем примере GDI.
HDC hdc;
PAINTSTRUCT ps;
Pen* myPen;
Graphics* myGraphics;
hdc = BeginPaint(hWnd, &ps);
myPen = new Pen(Color(255, 255, 0, 0), 3);
myGraphics = new Graphics(hdc);
myGraphics->DrawLine(myPen, 20, 10, 200, 100);
delete myGraphics;
delete myPen;
EndPaint(hWnd, &ps);
Ручки, кисти, пути, изображения и шрифты в качестве параметров
В предыдущих примерах показано, что объекты Пера могут создаваться и поддерживаться отдельно от графического объекта, который предоставляет методы рисования. Объекты Brush, GraphicsPath, Image и Font также можно создавать и поддерживать отдельно от объекта Graphics. Многие методы рисования, предоставляемые классом Графики, получают объект Brush, GraphicsPath, Image или Font в качестве аргумента. Например, адрес объекта Brush передается в качестве аргумента методу FillRectangle, а адрес объекта GraphicsPath передается в качестве аргумента методу Graphics::D rawPath. Аналогичным образом адреса объектов Image и Font передаются в методы DrawImage и DrawString. Это отличается от GDI, в котором вы выбираете кисть, путь, изображение или шрифт в контекст устройства, а затем передаете дескриптор контексту устройства в качестве аргумента функции рисования.
Перегрузка метода
Многие из методов GDI+ перегружены; То есть несколько методов используют одно и то же имя, но имеют разные списки параметров. Например, метод DrawLine класса Graphics поставляется в следующих формах:
Status DrawLine(IN const Pen* pen,
IN REAL x1,
IN REAL y1,
IN REAL x2,
IN REAL y2);
Status DrawLine(IN const Pen* pen,
IN const PointF& pt1,
IN const PointF& pt2);
Status DrawLine(IN const Pen* pen,
IN INT x1,
IN INT y1,
IN INT x2,
IN INT y2);
Status DrawLine(IN const Pen* pen,
IN const Point& pt1,
IN const Point& pt2);
Все четыре варианта DrawLine выше получают указатель на объект Pen, координаты начальной точки и координаты конечной точки. Первые два варианта получают координаты в виде чисел с плавающей запятой, а последние два варианта получают координаты в виде целых чисел. Первые и третие варианты получают координаты в виде списка четырех отдельных чисел, а второй и четвертый варианты получают координаты в виде пары объектов Point (или PointF).
Больше нет текущей позиции
Обратите внимание, что в методах DrawLine , показанных ранее, начальная точка и конечная точка строки получаются в качестве аргументов. Это отклонение от схемы GDI, в которой вы вызываете MoveToEx , чтобы задать текущую позицию пера, за которой следует LineTo , чтобы нарисовать линию начиная с (x1, y1) и заканчивая (x2, y2). GDI+ в целом отказался от понятия текущей позиции.
Отдельные методы для рисования и заливки
GDI+ является более гибким, чем GDI, когда дело доходит до рисования контуров и заполнения интерьеров фигур, таких как прямоугольники. GDI имеет функцию прямоугольника, которая рисует контур и заполняет интерьер прямоугольника на одном шаге. Контур рисуется с выбранным пером, и интерьер заполняется выбранной кистью в данный момент.
hBrush = CreateHatchBrush(HS_CROSS, RGB(0, 0, 255));
hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
SelectObject(hdc, hBrush);
SelectObject(hdc, hPen);
Rectangle(hdc, 100, 50, 200, 80);
GDI+ имеет отдельные методы для рисования контура и заполнения интерьера прямоугольника. Метод DrawRectangle класса Graphics имеет адрес объекта Pen в качестве одного из его параметров, а метод FillRectangle имеет адрес объекта Brush в качестве одного из его параметров.
HatchBrush* myHatchBrush = new HatchBrush(
HatchStyleCross,
Color(255, 0, 255, 0),
Color(255, 0, 0, 255));
Pen* myPen = new Pen(Color(255, 255, 0, 0), 3);
myGraphics.FillRectangle(myHatchBrush, 100, 50, 100, 30);
myGraphics.DrawRectangle(myPen, 100, 50, 100, 30);
Обратите внимание, что методы FillRectangle и DrawRectangle в GDI+ получают аргументы, указывающие левый край прямоугольника, верхнюю, ширину и высоту. Это отличается от функции прямоугольника GDI, которая принимает аргументы, указывающие левый край прямоугольника, правый край, верхний и нижний. Кроме того, обратите внимание, что конструктор для класса Color в GDI+ имеет четыре параметра. Последние три параметра — обычные красные, зеленые и синие значения; первым параметром является альфа-значение, указывающее степень, в которой рисуемый цвет смешается с цветом фона.
Создание регионов
GDI предоставляет несколько функций для создания регионов: CreateRectRgn, CreateEllpticRgn, CreateRoundRectRgn, CreatePolygonRgn и CreatePolygonRgn. Вы можете ожидать , что класс Region в GDI+ имеет аналогичные конструкторы, которые принимают прямоугольники, многоточие, округленные прямоугольники и многоугольники в качестве аргументов, но это не так. Класс Region в GDI+ предоставляет конструктор, который получает ссылку на объект Rect и другой конструктор, который получает адрес объекта GraphicsPath. Если вы хотите создать область на основе многоточия, округленного прямоугольника или многоугольника, можно легко сделать это, создав объект GraphicsPath (который содержит многоточие, например) и передав адрес этого объекта GraphicsPath конструктору Region.
GDI+ упрощает формирование сложных областей путем объединения фигур и путей. Класс Region имеет методы Union и Intersect , которые можно использовать для расширения существующего региона путем или другим регионом. Одна из хороших функций схемы GDI+ заключается в том, что объект GraphicsPath не уничтожается при передаче в качестве аргумента конструктору Region. В GDI можно преобразовать путь в регион с помощью функции PathToRegion , но путь уничтожается в процессе. Кроме того, объект GraphicsPath не уничтожается при передаче его адреса в качестве аргумента в метод Union или Intersect, чтобы использовать заданный путь в качестве стандартного блока для нескольких отдельных регионов. Это показано в следующем примере. Предположим, что onePath — это указатель на объект GraphicsPath (простой или сложный), который уже инициализирован.
Region region1(rect1);
Region region2(rect2);
region1.Union(onePath);
region2.Intersect(onePath);