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


Изменения в модели программирования

В следующих разделах описано несколько способов программирования с помощью 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);