Рисование линий произвольного стиля
Как мы уже говорили, вы не можете создать перо для рисования пунктирных, штрих-пунктирных или штриховых линий толщиной больше одного пиксела. Однако в некоторых случаях у вас может возникнуть необходимость в рисовании таких линий.
В программном интерфейсе GDI есть функция с именем LineDDA, которая позволяет рисовать любые линии (правда, основная работа по рисованию линий при этом будет возложена на программиста).
Функция LineDDA имеет следующий прототип:
void WINAPI LineDDA( int nxStart, int nyStart, // начальная точка int nxEnd, int nyEnd, // конечная точка LINEDDAPROC lnddaprc, // адрес функции для рисования LPARAM lParam); // дополнительные параметрыПервые четыре параметра этой функции определяют координаты начальной и конечной точки, между которыми надо нарисовать линию.
Через параметр lnddaprc передается указатель на функцию рисования, которая является функцией обратного вызова, определяемой программистом. Эта функция получает управление много раз, она вызывается для каждой точки рисуемой линии.
Для режима STRICT тип LINEDDAPROC определен в файле windows.h следующим образом:
typedef void (CALLBACK* LINEDDAPROC)(int, int, LPARAM);Последний параметр предназначен для передачи дополнительных данных в функцию рисования.
Приведем прототип функции рисования (для функции можно использовать любое имя):
void CALLBACK _exportLineProc(int xPos, int yPos, LPARAM lParam);Первые два параметра представляют собой координаты точки, для рисования которых вызвана функция. Последний параметр соответствует последнему параметру функции LineDDA и содержит передаваемое этой функции значение.
Пример использования функции LineDDA вы можете найти ниже в разделе "Приложение DASHLINE".
Рисование замкнутых фигур
Помимо линий, приложения Windows могут использовать функции GDI для рисования замкнутых закрашенных или незакрашенных фигур, таких как прямоугольники, эллипсы, многоугольники с прямыми и скругленными углами и т. д.
Для закрашивания внутренней области замкнутых фигур используется кисть, задаваемая как атрибут контекста отображения. Внешний контур фигуры обводится пером, которое также выбирается в контекст отображения. Учитываются и остальные атрибуты, установку которых мы рассмотрели для функций рисования линий, такие, как режим отображения, режим фона, код растровой операции.
Мы начнем изучение функций GDI, предназначенных для рисования замкнутых фигур, с функций рисования прямоугольников.
Рисование прямоугольника
Простейшая функция, с помощью которой можно нарисовать прямоугольник, называется Rectangle :
BOOL WINAPI Rectangle( HDC hdc, // идентификатор контекста отображения int nxTL, // координата x верхнего левого угла int nyTL, // координата y верхнего левого угла int nxBR, // координата x правого нижнего угла int nyBR); // координата y правого нижнего угла
Функция Rectangle рисует прямоугольник для контекста отображения hdc, возвращая значение TRUE в случае успеха или FALSE при ошибке.
Назначение остальных параметров иллюстрируется рис. 2.17.
Рис. 2.17. Рисование прямоугольника
Как видно из этого рисунка, последние четыре параметра функции задают координаты верхнего левого и нижнего правого угла прямоугольника.
В зависимости от стиля пера граница фигуры может находится полностью внутри прямоугольника, заданного координатами (nxTL, nyTL), (nxBR,nyBR) или выходить за его пределы (см. рис. 2.14). Если выбрать стиль пера PS_NULL, граница фигуры станет невидимой.
В зависимости от кисти, выбранной в контекст отображения, внутренность прямоугольника может быть закрашенной в тот или иной цвет, заштрихована одним из нескольких способов (как показано на рис. 2.16) или закрашена с помощью любого битового изображения размером 8х8 пикселов.
С помощью функции RoundRect можно нарисовать прямоугольник со скругленными углами (рис. 2.18).
Рис. 2.18. Прямоугольник со скругленными углами
По сравнению с функцией Rectangle функция RoundRect имеет два дополнительных параметра nxEllipse и nyEllipse, определяющих форму и радиус закругления:
BOOL WINAPI RoundRect( HDC hdc, // идентификатор контекста отображения int nxTL, // координата x верхнего левого угла int nyTL, // координата y верхнего левого угла int nxBR, // координата x правого нижнего угла int nyBR, // координата y правого нижнего угла int nxEllipse, // ширина эллипса int nyEllipse); // высота эллипсаЕсть и другие функции, которые можно использовать для рисования прямоугольников.
Функция FillRect закрашивает прямоугольную область окна заданной кистью:
int WINAPI FillRect( HDC hdc, // идентификатор контекста отображения const RECT FAR* lprc, // указатель на структуру RECT HBRUSH hbrush); // идентификатор кисти для закрашиванияПараметр lprc должен указывать на структуру типа RECT, в которую следует записать координаты закрашиваемой прямоугольной области. Правая и нижняя граница указанной области не закрашивается.
Независимо от того, какая кисть выбрана в контекст отображения, функция FillRect будет использовать для закраски кисть, указанную параметром hbrush.
Учтите, что правильная работа функции FillRect гарантируется только в том случае, когда значение поля bottom структуры RECT больше значения поля top, а значение поля right больше значения поля left.
Для закрашивания границы прямоугольной области (т. е. для рисования прямоугольной рамки) можно использовать функцию FrameRect :
int WINAPI FrameRect( HDC hdc, // идентификатор контекста отображения const RECT FAR* lprc, // указатель на структуру RECT HBRUSH hbrush); // идентификатор кисти для закрашиванияПараметры этой функции аналогичны параметрам функции FillRect.
Ширина пера, используемого для рисования рамки, всегда равна одной логической единице. Структура RECT должна быть подготовлена таким же образом, что и для функции FillRect, т. е. значение поля bottom структуры RECT должно быть больше значения поля top, а значение поля right - больше значения поля left.
Значение, возвращаемое функциями FillRect и FrameRect не используется, приложения должны его игнорировать.
Используя функцию InvertRect , вы можете инвертировать содержимое прямоугольной области, заданной параметром lprc:
void WINAPI InvertRect(HDC hdc, const RECT FAR* lprc);Есть еще одна интересная функция, предназначенная для рисования прямоугольников. Она имеет имя DrawFocusRect :
void WINAPI DrawFocusRect(HDC hdc, const RECT FAR* lprc);Эта функция рисует прямоугольную рамку, предназначенную для выделения окна, имеющего фокус ввода.
Функция DrawFocusRect имеет три интересные особенности.
Во-первых, для рисования используется растровая операция "ИСКЛЮЧАЮЩЕЕ ИЛИ". Это приводит к тому, что для удаления нарисованной таким образом рамки ее достаточно нарисовать еще раз на том же месте.
Вторая особенность заключается в том, что для использования этой функции не нужно выбирать перо, рисующее пунктирную линию. Функция DrawFocusRect рисует пунктирную линию с нестандартным, очень близким расположением точек.
Третья особенность заключается в том, что перед использованием этой функции необходимо установить режим отображения MM_TEXT.
Первые две особенности позволяют использовать ее для рисования рамки выделения произвольных участков изображения на экране монитора (при помощи мыши).
В заключение отметим, что в программном интерфейсе Windows нет функции для рисования квадрата и круга. Эти фигуры являются частными случаями, соответственно, прямоугольника и эллипса, поэтому для рисования, например, квадрата, вы должны использовать одну из только что описанных функций. Для сохранения пропорций проще всего использовать одну из метрических систем координат.
Рисование эллипса
Для рисования эллипса вы можете использовать функцию Ellipse :
BOOL WINAPI Ellipse( HDC hdc, // идентификатор контекста отображения int nxTL, // координата x верхнего левого угла int nyTL, // координата y верхнего левого угла int nxBR, // координата x правого нижнего угла int nyBR); // координата y правого нижнего углаПервый параметр этой функции указывает идентификатор контекста отображения, остальные - координаты верхнего левого и правого нижнего углов прямоугольника, в который должен быть вписан эллипс (рис. 2.19).
Рис. 2.19. Рисование эллипса
Рисование сегмента эллипса
Сегмент эллипса (рис. 2.20) можно нарисовать при помощи функции Chord :
BOOL WINAPI Chord( HDC hdc, // идентификатор контекста отображения int nxLeft, int nyTop, // верхий левый угол int nxRight, int nyBottom, // правый нижний угол int nxStart, int nyStart, // начало дуги int nxEnd, int nyEnd); // конец дугиПараметры этой функции аналогичны параметрам рассмотренной нами ранее функции Arc.
Рис. 2.20. Рисование сегмента эллипса
Рисование сектора эллипса
Для рисования сектора эллипса (рис. 2.21) следует использовать функцию Pie , аналогичную по своим параметрам функциям Arc и Chord:
BOOL WINAPI Pie( HDC hdc, // идентификатор контекста отображения int nxLeft, int nyTop, // верхний левый угол int nxRight, int nyBottom, // правый нижний угол int nxStart, int nyStart, // начало дуги int nxEnd, int nyEnd); // конец дугиРис. 2.21. Рисование сектора эллипса
Рисование многоугольников
Рисование многоугольников (рис. 2.22) выполняется функцией Polygon , аналогичной по своим параметрам функции Polyline, с помощью которой рисуются ломаные линии:
BOOL WINAPI Polygon( HDC hdc, // идентификатор контекста отображения const POINT FAR* lppt,// указатель на массив структур POINT int cPoints); // размер массиваЧерез параметр hdc передается идентификатор контекста отображения.
Параметр lppt указывает на массив структур POINT, в котором должны находится координаты вершин многоугольника. Параметр cPoints определяет размер этого массива.
Функция Polygon возвращает TRUE при нормальном завершении или FALSE при ошибке. Она не использует текущую позицию пера и не изменяет ее.
Рис. 2.22. Рисование многоугольника
В массиве структур POINT, определяющих вершины многоугольника, каждая вершина должна быть указана один раз. Функция Polygon автоматически замыкает ломаную линию, образующую многоугольник.
С помощью функции PolyPolygon можно нарисовать одновременно несколько многоугольников:
BOOL WINAPI PolyPolygon( HDC hdc, // идентификатор контекста отображения const POINT FAR*lppt, // указатель на массив структур POINT int FAR* lpnPolyCounts, // адрес массива количества точек // в многоугольниках int cPolygons); // количество многоугольниковПервый параметр hdc, как обычно, задает контекст отображения.
Параметр cPolygons определяет количество многоугольников, которые нужно нарисовать.
Параметр lppt должен содержать указатель на массив структур типа POINT, содержащий координаты вершин всех многоугольников.
И, наконец, через параметр lpnPolyCounts передается указатель на массив целых чисел. Каждое число в этом массиве определяет количество точек в соответствующем многоугольнике.
В отличие от функции Polygon, функция PolyPolygon не замыкает автоматически ломаную линию, образующую многоугольник.
В контексте отображения имеется атрибут, влияющий на способ закрашивания для самопересекающихся многоугольников. По умолчанию выбран режим ALTERNATE , в котором эти области не закрашиваются (закрашиваются только те области, которые расположены между нечетными и четными сторонами многоугольника).
С помощью функции SetPolyFillMode вы можете изменить значение этого атрибута на WINDING . В этом режиме для того чтобы определить, надо ли закрашивать область многоугольника, учитывается направление, в котором был нарисован этот многоугольник. Каждая сторона многоугольника может быть нарисована в направлении либо по часовой стрелке, либо против часовой стрелки. Если воображаемая линия, нарисованная в направлении из внутренней области многоугольника в наружную, пересекает сегмент, нарисованный в направлении по часовой стрелке, содержимое некоторого внутреннего счетчика увеличивается на единицу. Если же эта линия пересекает сегмент, нарисованный против часовой стрелки, содержимое счетчика уменьшается на единицу. Область закрашивается только в том случае, если содержимое счетчика не равно нулю.
Немного позже вы сможете изучить этот алгоритм с помощью приложения LINER.
Приведем прототип функции SetPolyFillMode:
int WINAPI SetPolyFillMode(HDC hdc, int fnMode);Параметр fnMode, определяющий режим закрашивания многоугольников, может принимать значения ALTERNATE или WINDING. Функция возвращает код старого режима закрашивания.
Вы можете определить используемый в данный момент режим закрашивания многоугольников с помощью функции GetPolyFillMode :
int WINAPI GetPolyFillMode(HDC hdc);Выбор кисти
Для закрашивания внутренней области замкнутых фигур вы можете использовать встроенные кисти, или кисти, созданные вашим приложением. Последние необходимо удалять после использования.