Основы графического вывода

Глобальные системы координат GDI. Отображение основных графических объектов. Основные и дополнительные средства для рисования линий. Растровые изображения и метафайлы. Обзор и создание зависимых и независимых от графического устройства битмапов.

Рубрика Программирование, компьютеры и кибернетика
Вид лекция
Язык русский
Дата добавления 24.06.2009
Размер файла 498,8 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

FLOAT eDy;

} XFORM;

Функция GetWorldTransform возвращает текущую матрицу преобразований, SetWorldTransform позволяет задать новую матрицу, а функции ModifyWorldTransform и CombineWorldTransfrom используются для изменения и вычисления коэффициентов матрицы. Считается, что матрица XFORM используется следующим образом:

В этой форме матрица XFORM сделана квадратной, добавлением третьего столбца с неизменяемыми значениями, равно как и вектора сделаны трехкомпонентными добавлением еще одного компонента, равного 1. Векторная форма записи этой матрицы будет полезна при рассмотрении функции ModifyWorldTransform, которая выполняет умножение текущей матрицы преобразований на заданную вами. Такое умножение может выполняться двумя способами (умножение матриц не коммутативно): если параметр dwMode равен MWT_LEFTMULTIPLY, то задаваемая вами матрица используется как левый операнд умножения, а текущая -- как правый; а если dwMode равен MWT_RIGHTMULTIPLY, то задаваемая вами матрица будет располагаться справа от текущей. Еще одно возможное значение параметра dwMode -- MWT_IDENTITY -- устанавливает стандартную матрицу преобразований, при этом параметр lpxformMatrix не используется.

Последняя функция CombineTransform служит для вычисления новой матрицы преобразований lpxformResult по двум заданным матрицам lpxformA, lpxformB, которые рассматриваются как матрицы, задающие два последовательно выполняемых преобразования. Здесь интересно сделать обзор основных простейших преобразований систем координат и задаваемых для них коэффициентов. Это позволит любое сложное преобразование описать как последовательность примитивных действий и построить требуемую матрицу автоматически.

Перемещение (translation). Перемещение осуществляется добавлением постоянных величин к координатам x (коэффициент Dx) и y (коэффициент Dy). При этом коэффициенты M11 и M12 должны быть равны 1, а M12 и M21 равны 0. Формула в матричном виде раскрывается следующим образом:

x' = x + Dx

y' = y + Dy

Масштабирование (scaling) и зеркальное отражение (reflection). Обе эти операции выполняются одним способом, для их задания необходимо указать масштабные коэффициенты M11 (масштаб по оси X) и M22 (масштаб по оси Y).

Отрицательные значения коэффициентов соответствуют перевернутому виду. Для получения зеркального отражения задают коэффициенты равными -1.

x' = x * M11

y' = y * M22

`Поворот (rotation). Для задания коэффициентов необходимо узнать угол поворота a. Если он известен, то коэффициенты M11 и M22 оба будут равны cos a, коэффициент M12 будет равен sin a, а коэффициент M21 = _sin a. То есть для задания поворота необходимо вычислить коэффициенты M11 и M12, а коэффициенты M22 и M21 получаются из уже вычисленных: M22 = M11 и M21 = -M12.

x' = x * M11 - y * M21 = x * cos a - y * sin a

y' = x * M12 + y * M22 = x * sin a + y * cos a

Сдвиг (shear). Для задания сдвига (описание неперпендикулярных осей координат) необходимо задать два коэффициента M12 и M21, задающих величину сдвига осей. При этом коэффициенты M11 и M22 оба равны 1.

x' = x + y * M21

y' = x * M12 + y

Внимание! Помимо возможности использовать функции для изменения матрицы преобразований режим GM_ADVANCED отличается от GM_COMPATIBLE рисованием прямоугольников и эллипсов -- нижняя и правая границы в этом режиме включаются в рисуемый объект и рисованием дуг -- они всегда рисуются против часовой стрелки.

В этом вопросе в документации встречаются некоторые неточности. Так, например, обычно утверждается, что для использования функций по заданию или изменению матрицы преобразований глобальных координат необходимо работать в расширенном режиме (GM_ADVANCED), а обратный переход от GM_ADVANCED к GM_COMPATIBLE осуществляется только при стандартной матрице преобразований. Вторая часть утверждений не совсем корректна.

Режим GM_ADVANCED отличается от GM_COMPATIBLE тем, что он позволяет изменять матрицу преобразований плюс включение нижней и правой границ ограничивающего прямоугольника в рисуемый объект, плюс рисование дуг всегда против часовой стрелки плюс некоторые особенности отображения растровых шрифтов. Сама матрица преобразований используется постоянно, вне зависимости от текущего режима, в то время как в режиме GM_COMPATIBLE вы ее просто не можете изменять. Переключение из расширенного режима в совместимый вовсе не запрещается и корректно выполняется системой.

Объекты GDI

При рассмотрении таблицы атрибутов контекста устройства вы наверное заметили, что значительное количество атрибутов изменяются с помощью функции SelectObject. Эти атрибуты представлены специальными структурами данных, описывающими так называемые объекты GDI. Эти объекты описывают некоторые примитивы GDI, используемые при выводе изображений. В качестве примера можно привести перья (pen) и кисти (brush), применяемые при рисовании линий и закраске фона фигур.

Объекты GDI не имеют ничего общего с объектами ООП, они являются объектами с только точки зрения Windows и принадлежат модулю GDI. Фактически такой объект реализован как специальная структура (иногда несколько структур) данных, управление которыми осуществляется системой, а вы можете этими данными манипулировать, используя хендл. Эти структуры данных не являются интерактивными и они не получают никаких сообщений. Так что использование в данном случае термина объект является не слишком удачным, хотя и общепринятым.

Общие правила

Объектов GDI существует достаточно большое количество, но все они имеют сходные правила применения. Перед тем как приступить к их использованию целесообразно рассмотреть основные правила применения объектов GDI.

1) Объекты могут создаваться и уничтожаться в любой момент времени, причем они могут сохраняться и между обработкой разных сообщений. Поэтому объекты часто создаются в функции WinMain или при обработке сообщения WM_CREATE, а уничтожаются, соответственно, либо при обработке сообщения WM_DESTROY, либо перед выходом из функции WinMain.

2) Все созданные объекты обязательно должны быть уничтожены до завершения приложения. Windows сам не уничтожает оставленных приложением объектов, что может привести к быстрому исчерпанию ресурсов. Это связано с тем, что объекты GDI размещаются не в глобальной памяти Windows, а в локальной памяти модуля GDI (USER.EXE или GDI32.EXE). Для этого модуля ограничен максимальный размер локальной кучи в 64К для 16ти разрядных (Windows 3.x, Windows-95) и 4М для 32х разрядных (Windows NT, Windows-98) графических подсистем, причем объекты GDI, созданные каким-либо приложением, с этим приложением не ассоциируются, в следствие чего автоматического уничтожения этих объектов не происходит Исключение -- Windows NT. В этой системе для каждого запущенного приложения загружается своя копия системных модулей, включая GDI32.EXE; Этот механизм не настолько громоздок, как кажется, за счет специальных механизмов защиты страниц «копирование при записи». Достоинство -- высокая защищенность, так как приложение может навредить только себе, даже если оно разрушит или не освободит системные объекты. В этом случае при завершении работы приложения все ресурсы, созданные им, автоматически освобождаются. Однако очень надеяться на эту особенность не стоит -- если ресурсы не освобождать вовремя, то размер файла подкачки страниц может существенно увеличиться, в связи с чем возникнет вопрос о наличии свободного дискового пространства..

3) Перед уничтожением объекта вы должны быть уверены, что он не выбран контекст устройства. Если объект в момент уничтожения используется, то он не будет уничтожен.

4) Объекты GDI кэшируется системой. То есть повторное создание часто используемого объекта осуществляется существенно быстрее, чем в первый раз.

5) Помимо создаваемых в приложении объектов, система может вам предоставить некоторые стандартные, которые соответствуют наиболее часто применяемым объектам. Например -- тонкое перо черного цвета или кисть белого цвета и т.д. Стандартные объекты нельзя уничтожать. Вообще-то система должна заметить, что предпринимается попытка уничтожения стандартного объекта и запретить эту операцию. Но ошибки встречаются везде, даже в системе, так что лучше не уповать на ее надежность.

6) Разные объекты имеют хендлы со специфичными названиями HPEN, HBRUSH, HFONT и др. Вы можете применять просто HANDLE или HGDIOBJ вместо всех этих типов. Применение специфичных типов может быть предпочтительным при осуществлении строгой проверки типов. В разных API и реализациях windows.h для разных компиляторов стандартные функции GDI могут использовать несколько различающиеся типы хендлов. Так, например, функция SelectObject, которая может работать с объектами разных типов, обычно декларирована как функция, получающая хендл типа HGDIOBJ. Однако в старых 16ти разрядных версиях windows.h она может быть описана как получающая просто HANDLE. Часто может быть удобнее применять макросы, определенные в windowsx.h, которые осуществляют соответствующие операции с необходимым приведением типов. Например, вместо SelectObject можно использовать макросы SelectPen, SelectBrush, SelectFont и т.д., смотря по типу выбираемого объекта.

7) Стандартные объекты можно получить с помощью функции

HGDIOBJ GetStockObject (nIndex);

Она возвращает хендл стандартного объекта. Нужный объект задается параметром nIndex. Например, это может быть BLACK_PEN, WHITE_BRUSH, SYSTEM_FONT и т.д. Подробнее -- см. в описании функции. Либо, вместо этой универсальной функции можно применять макросы, определенные в windowsx.h: GetStockPen, GetStockBrush, GetStockFont и пр. Эти макросы будут возвращать результат соответствующего типа (HPEN, HBRUSH, HFONT, ...). При использовании макросов надо проследить, что бы индекс требуемого объекта соответствовал используемому макросу. Например, вы можете по ошибке использовать макрос GetStockPen для получения хендла стандартного шрифта -- так как макрос в итоге обратиться к универсальной функции GetStockObject, то фатальной ошибки не возникнет, просто возвращаемый результат будет приведен к некорректному типу (в примере: HPEN вместо HFONT).

8) Для создания собственных объектов применяются функции, начинающиеся со слова Create... Например, CreatePen или CreateSolidBrush.

9) Полученный объект (стандартный или созданный вами) выбирается в контекст устройства функцией:

HGDIOBJ SelectObject (hDC, hObject);

Эта функция возвращает хендл объекта того-же типа, выбранного ранее в этот контекст. В большинстве случаев может быть удобнее воспользоваться вместо функции SelectObject макросами из windowsx.h, предназначенными для работы с конкретными объектами:

HPEN SelectPen (hDC, hPen);

HBRUSH SelectBrush (hDC, hBrush);

HFONT SelectFont (hDC, hFont);

HBITMAP SelectBitmap (hDC, hBitmap);

10) Для получения информации об объекте применяется функция

int GetObject (hObject, nSize, lpvStruct);

где hObject -- хендл объекта GDI, информацию о котором вы запрашиваете, lpvStruct -- указатель на структуру данных, которая будет заполняться информацией об объекте; для объектов разных типов определены разные структуры (BITMAP, LOGPEN, LOGBRUSH, LOGFONT и т.д.), nSize -- размер этой структуры.

11) Объект уничтожается функцией

BOOL DeleteObject (hObject);

Эта функция удаляет указанный объект, если только это не стандартный объект и если он не выбран в контекст устройства. Вместо одной универсальной функции в windowsx.h можно найти макросы, удаляющие объекты конкретных типов: DeletePen, DeleteBrush, DeleteFont и т.д.

Обычное использование

Сейчас мы рассмотрим обычные схемы использования объектов. В самом типичном случае объект создается непосредственно тогда, когда он используется, и уничтожается сразу после освобождения из контекста устройства. Несмотря на часто выполняемую операцию создания и уничтожения этот метод является предпочтительным, так как до минимума сводится количество одновременно существующих объектов (что снижает требования к объему свободных ресурсов GDI), а затраты времени минимизируются благодаря кэшированию объектов системой.

В качестве примера мы будем использовать только один объект GDI -- перо, так как применение всех остальных типов объектов аналогично.

void Cls_OnPaint (HWND hwnd)

{PAINTSTRUCT ps;

HPEN hpenOld, hpenRed, hpenBlue;

BeginPaint (hwnd, &ps);

// создаем перья:

hpenRed = CreatePen (PS_SOLID, 0, RGB (255,0,0));

hpenBlue = CreatePen (PS_SOLID, 0, RGB (0,0,255));

// выбираем его в контекст и запоминаем прежнее:

hpenOld = (HPEN)SelectObject (ps.hdc, (HGDIOBJ)hpenRed);

... // осуществляем рисование красным пером

// выбираем другое перо, причем запоминать предыдущее не надо - оно

// и так известно - это hpenRed

SelectObject (ps.hdc, (HGDIOBJ)hpenBlue);

... // осуществляем рисование синим пером

// освобождаем созданное перо из контекста (то есть выбираем первоначальное)

SelectObject (ps.hdc, (HGDIOBJ)hpenOld);

// и удаляем созданные

DeleteObject ( (HGDIOBJ)hpenRed);

DeleteObject ( (HGDIOBJ)hpenBlue);

EndPaint (hwnd, &ps);}

Этот пример иллюстрирует все основные шаги по работе с создаваемыми объектами GDI. Однако в реальной жизни он используется не слишком часто -- как правило при рисовании используется не один объект данного типа, а несколько. Это приводит к появлению большого количества переменных, как-то: hpen1, hpen2, ..., hpen100. Читаемость такого текста сравнительно невелика, да и вероятность запутаться остается высокой. Другое соображение -- часто встречающееся приведение типов. В этом случае удобнее использовать макросы из windowsx.h. В третьих -- сохранять исходный объект для восстановления его в контексте устройства не обязательно. Если существуют стандартные объекты данного типа, то вместо восстановления исходного можно перед удалением объектов выбрать в контекст любой стандартный того же типа (скажем, стандартных регионов или битмапов не определено -- для них рекомендуется сохранять исходный).

В результате часто используются целые комбайны из функций GDI, как в приводимом ниже примере:

void Cls_OnPaint (HWND hwnd)

{PAINTSTRUCT ps;

BeginPaint (hwnd, &ps);

// создаем красное перо и выбираем его в контекст;

// прежнее НЕ запоминаем:

SelectPen (ps.hdc, CreatePen (PS_SOLID, 0, RGB (255,0,0)));

... // осуществляем рисование красным пером

// создаем и выбираем синее перо;

// предыдущее - созданное нами красное - сразу уничтожаем

DeletePen (SelectPen (ps.hdc, CreatePen (PS_SOLID, 0, RGB (0,0,255))));

... // осуществляем рисование синим пером

// освобождаем синее перо из контекста и уничтожаем его

DeletePen (SelectPen (ps.hdc, GetStockPen (BLACK_PEN)));

EndPaint (hwnd, &ps);}

В этом случае экономятся как локальные переменные, так и дополнительно снижаются требования к объему свободных ресурсов GDI, хотя к чтению подобных длинных выражений надо привыкать. Единственное, за чем надо внимательно следить -- что бы при выборе нового объекта вместо предыдущего, созданного вами, использовалась функция DeleteObject (или эквивалентный макрос), а при выборе нового объекта вместо стандартного эта функция не использовалась.

Более редкий случай -- когда объекты создаются при обработке WM_CREATE и уничтожаются при обработке WM_DESTROY (или при запуске и завершении приложения). Этот способ используется редко, так как требуется описание дополнительных статических переменных и, кроме того, интенсивнее расходуются ресурсы GDI.

LRESULT WINAPI _export WinProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{PAINTSTRUCT ps;

static HPEN hpenRed; // хендл пера должен сохраняться в промежутке

// между обработкой сообщений

switch (uMsg) {case WM_CREATE:

...

hpenRed= CreatePen (PS_SOLID, 0, RGB (255,0,0));

break;

case WM_PAINT:

BeginPaint (hWnd, &ps);

SelectPen (ps.hdc, hpenRed);

... // здесь мы используем выбранный объект

// теоретически, объект сохраняется и после уничтожения контекста -

// так что мы можем не заменять его на стандартный; правда так делать

// не рекомендуется По-видимому, некоторые подобные рекомендации сделаны для обеспечения возможной совместимости с другими системами в будущем. Так, например, при работе в X-Windows (в основном UNIX-машины), при удалении контекста удаляются все объекты, выбранные в него. Если оставаться в рамках Windows или Win32 API, то выбранные в контекст устройства объекты GDI вовсе не обязательно заменять на стандартные перед освобождением контекста.

EndPaint (hWnd, &ps);

break;

case WM_DESTROY:

DeletePen (hpenRed);

...

break;

...

default:

return DefWindowProc (hwnd, uMsg, wParam, lParam);}

return 0L;}

Довольно часто, если объект создается на все время жизни окна, вместо статической переменной используются связанные с окном данные: либо размещенные в структуре окна (см. функции GetWindowLong, SetWindowLong), либо списки свойств окна (Property) (об этом см. методы связывания данных с окном).

Отображение основных графических объектов

В процессе отображения основных графических примитивов (например, прямых линий, прямоугольников и пр.) участвует большое количество атрибутов контекста устройства, влияющих на видимый результат. Условно можно выделить отображение отдельных пикселей, рисование линий и рисование заполненных фигур.

При отображении отдельных пикселей атрибуты контекста устройства практически не используются -- вы просто указываете цвет и положение пикселя, который хотите отобразить. На результат влияют только область отображения и характеристики устройства.

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

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

Задание цвета

При отображении любых графических объектов необходимо задавать их цвета. Сложности задания цвета начинаются из-за того, что различная аппаратура может воспроизводить только некоторое конечное число цветов. Одновременно вам может понадобиться осуществлять вывод сразу на несколько устройств, возможности которых по отображению цвета существенно различаются. Например -- любой текстовой или графический редактор может взаимодействовать как с дисплеем, способным воспроизводить от нескольких цветов до миллионов цветов и принтером, который часто является монохромным.

Для обеспечения универсальности в GDI принято, что цвет обозначается с помощью 24х битового параметра типа COLORREF. Этот параметр реально соответствует одному двойному слову, самый старший байт которого не используется. Младшие три байта задают интенсивности трех основных компонент цвета -- красной, зеленой и синей. Каждая компонента задается своим байтом, так что предельный диапазон ее изменения лежит от 0 до 255. Это позволяет задавать до 16 777 216 различных цветов.

Для удобного задания параметра типа COLORRREF используется специальный макрос RGB, который из трех по отдельности указанных компонент формирует одно двойное слово.

COLORREF RGB (byRed, byGreen, byBlue);

Конечно, Windows не всегда может использовать 24х битовый цвет непосредственно, так как аппаратура может поддерживать от 2 цветов (монохроматические устройства) до более чем 16 млн. цветов (режимы TrueColor и HighColor для современных видеоадаптеров). Вместо отображения указанного вами цвета, GDI будет подбирать ближайший цвет, который в состоянии воспроизвести данная аппаратура в данном режиме; такой цвет называется чистый (pure color).

Внимание! на монохромных устройствах существует только два чистых цвета: черный и белый. Поэтому все цвета, имеющие сумму яркостей трех составляющих менее 381, представляются черными, а больше -- белыми. Это может привести к неразличимости образа, если, например, вы по черному фону рисуете красную линию, или по белому -- светло-циановую.

В некоторых случаях GDI может использовать вместо чистого цвета смесь точек разных цветов, наиболее точно передающих желаемый цвет. Такой цвет называется смешанным (dithered color). Однако такая операция выполняется далеко не всегда. Так при выводе текста цвет символов будет чистым цветом; аналогично линии (за небольшим исключением) рисуются тоже чистым цветом.

Работа с отдельными пикселями

Рисование по отдельным точкам крайне редко используется в Windows, так как скорость осуществления подобной операции является исключительно низкой. Во всех случаях рекомендуется найти какой-либо другой способ отображения, а не рисовать по отдельным точкам.

Собственно, для рисования точек существуют всего две функции:

СOLORREF GetPixel (hDC, nX, nY);

COLORREF SetPixel (hDC, nX, nY, crColor);

Координаты nX и nY являются логическими координатами, определяющими позицию пикселя, цвет которого мы узнаем или изменяем. Независимо от принятой системы координат отображается один пиксель, даже если его размер соответствует нескольким логическим единицам.

Кроме того, задаваемый цвет пикселя автоматически преобразуется к ближайшему чистому цвету, который может быть воспроизведен аппаратурой.

Если используемый пиксель находится вне области рисования, то обе функции возвращают -1, а если пиксель находится внутри области рисования, то возвращаемое значение соответствует текущему цвету пикселя. Для функции SetPixel оно может отличаться от заданного crColor, указывая примененный чистый цвет (если ваша аппаратура не может отобразить требуемый цвет). Этот прием иногда используется для проверки возможностей устройства, хотя эффективнее анализировать возможности устройства с помощью функции GetDeviceCaps.

Рисование линий

В процессе рисования линии участвует сразу несколько атрибутов GDI (помимо атрибутов, выбирающих систему координат). Перед рисованием нужной вам линии вы должны настроить контекст устройства в соответствии с выполняемой операцией, установив нужные значения атрибутов. Коротко назначение этих атрибутов следующее:

Текущее перо (Pen).

Определяет вид проводимой линии -- толщину, цвет, стиль (сплошная или прерывистая). Перо является объектом GDI, поэтому при его использовании необходимо соблюдать правила работы с объектами GDI.

Текущая позиция пера (Pen Position).

Определяет точку из которой начнется рисование следующего отрезка линии. После рисования этого отрезка текущая точка перемещается в конец отрезка.

Цвет фона (Background Color).

Заполняет промежутки между штрихами прерывистой линии (а также фон под символами выводимого текста или промежутки между линиями штрихованных кистей -- об этом см. в обсуждении рисования заполненных фигур и обсуждении вывода текста).

Режим заполнения фона (Background Mode).

Определяет, надо-ли закрашивать промежутки между штрихами прерывистой линии цветом фона или оставить фон без изменений. Аналогично -- при выводе текста.

Режим рисования (Drawing Mode).

На практике рисование на контексте устройства рассматривается как сложный процесс переноса подготовленного вами изображения (например, образа рисуемой линии) на уже существующее в этом месте изображение. В процессе переноса выполняется некоторая операция, в результате которой получается результирующее изображение. Обычно такая операция -- простое копирование нового изображения на старое. Однако вы можете задать необходимую операцию, которую надо выполнять в процессе переноса изображения.

Направление рисования дуг эллипсов (Arc Direction).

Влияет только на результат рисования дуги эллипса (функции Arc, Pie и Chord). По умолчанию дуги рисуются против хода часовой стрелки, но вы можете изменить это направление. Пользоваться этой возможностью, вообще говоря, не рекомендуется, так как применение этой функции ограничено -- в Win32 API в расширенном режиме задания координат (см. SetGraphicsMode, GM_ADVANCED) дуги рисуются всегда против хода часовой стрелки и изменить это направление нельзя.

Собственно для рисования прямых линий необходимо всего две функции:

DWORD MoveTo (hDC, nX, nY); 0

BOOL MoveToEx (hDC, nX, nY, lpPoint);

BOOL LineTo (hDC, nX, nY);

Функция MoveToEx перемещает текущую точку пера в указанное место, не выполняя рисования. Последующий вызов функции LineTo осуществит рисование от текущей точки до указанной конечной отрезка. Нарисованный отрезок линии не включает в себя последнюю точку! Это сделано для удобства рисования ломанных линий из нескольких отрезков -- в этом случае любая точка ломанной будет нарисована только один раз. Если вам необходимо нарисовать отрезок обязательно включая последнюю точку -- продлите отрезок на один пиксель дальше (не забывайте, что вы задаете логические координаты, а удлинить отрезок надо на одну единицу устройства!). Если это сделать трудно (например отрезок наклонен под каким--то углом) то можно дополнительно нарисовать крохотный отрезок длиной 1 пиксель в любую сторону.

В случае Windows API часто применялась функция MoveTo, а не MoveToEx; Функция MoveTo возвращала информацию о прежнем положении текущей точки, упакованную в двойное слово. В Win32 API такая упаковка невозможна -- каждая координата уже представляет собой двойное слово -- поэтому функция MoveTo больше не поддерживается.

Возможен случай, когда надо нарисовать ломаную линию, состоящую из нескольких отрезков. Конечно, это легко сделать с помощью серии вызовов функции LineTo, но иногда может быть проще воспользоваться другой функцией:

BOOL Polyline (hDC, lpPoints, nCount);

Эта функция рисует ломаную линию, начальная, конечная и все точки перегиба которой заданы в массиве структур типа POINT (параметр lpPoints), содержащем nCount точек. Линия рисуется, начиная от первой точки и далее, соединяя последовательно отрезками все точки, вплоть до последней. Ломаная линия может быть незамкнутой, GDI не проводит замыкающего отрезка от последней точки к первой.

Еще одна функция GDI предназначена для рисования дуг:

BOOL Arc (hDC, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);

Для задания рисуемой дуги эллипса вы должны задать сначала сам эллипс, дуга которого будет изображаться, а затем задать начальную и конечную точки дуги. Эллипс задается описывающим его прямоугольником (причем нижняя и правая границы не включаются) -- параметры xLeft, yTop, xRight и yBottom, а начальная и конечная точки задаются параметрами xStart, yStart и xEnd, yEnd.

Рисунок 4. Рисование дуг эллипсов

Начальная и конечная точки могут не лежать на эллипсе. В этом случае GDI вычисляет точку пересечения эллипса с отрезком, соединяющим центр эллипса с указанной вами точкой. Дуга будет рисоваться между точками пересечения отрезков, направленных от центра эллипса к начальной и конечной точкам дуги в направлении против хода часовой стрелки (см. раздел «Направление рисования дуг»).

В случае применения Win32 API вы можете использовать еще несколько функций для рисования линий. Так две новых функции предназначены для рисования дуг:

BOOL ArcTo (hDC, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd); 1

BOOL AngleArc (hDC, nX, nY, dwRadius, eStartAngle, eSweepAngle); 1

Функция ArcTo аналогична функции Arc, за исключением того, что она сначала рисует отрезок от текущей точки до начальной точки дуги, затем рисует саму дугу и перемещает текущую точку в конечную точку нарисованной дуги. Функция AngleArc рисует дугу окружности, не эллипса. Для нее надо задать центр окружности (параметры nX, nY), радиус (dwRadius), начальный угол (eStartAngle) и угловую величину рисуемой дуги (eSweepAngle), в градусах. GDI не проверяет угловую величину дуги, она может превышать 3600.

Еще пара новых функций предназначена для рисования ломаных линий:

BOOL PolylineTo (hDC, lpPoints, nCount); 1

BOOL PolyPolyline (hDC, lpPoints, lpuCounts, nPolyCount); 1

Функция PolylineTo отличается от Polyline тем, что начинает рисование с отрезка от текущей точки до первой точки, указанной в массиве, а после прорисовки всех отрезков перемещает текущую точку в последнюю точку массива. Функция PolyPolyline может за одну операцию отобразить несколько ломаных линий. Координаты всех точек всех линий задаются массивом структур POINT (параметр lpPoints), число точек в каждой ломаной линии задается массивом целых чисел lpuCounts, а число ломаных, рисуемых этой функцией -- параметром nPolyCount.

Кроме того в Win32 API существуют функции для рисования кривых Безье:

BOOL PolyBezier (hDC, lpPoints, cPoints); 1

BOOL PolyBezierTo (hDC, lpPoints, cPoints); 1

Функция PolyBezier рисует линию состоящую из сегментов кривых Безье. Для задания каждого сегмента требуется указать четыре точки: начальную, две направляющие и конечная. Так как рисуется линия из нескольких сегментов, то конечная точка одного сегмента является в свою очередь начальной точкой другого сегмента. Таким образом кривая будет определяться набором из Npt = 1 + Nsegments*3; здесь Npt -- число точек для задания кривой, Nsegments -- число сегментов в кривой.

Используя функцию PolyBezier вы должны задать массив точек, определяющих начальную точку, две направляющие и конечную точку для первого сегмента кривой, затем по две направляющих и одной конечной для каждого последующего сегмента. Текущая точка при этом не используется.

Функция PolyBezierTo отличается тем, что текущая точка используется в качестве начальной точки первого сегмента. В этом случае в массиве должно содержаться на одну точку меньше -- только по две направляющих и одной конечной для каждого сегмента кривой. И, кроме того, после рисования кривой текущая точка будет перемещена в конечную точку последнего нарисованного сегмента.

Последняя рассматриваемая функция предназначена для рисования целого набора из прямых отрезков и кривых Безье за одну операцию:

BOOL PolyDraw (hDC, lpPoints, lpbyTypes, cCount); 1

Массивы структур POINT (lpPoints) и байтов (lpbyTypes) имеют одинаковое количество элементов; каждый элемент массива lpbyTypes определяет тип рисуемой линии из текущей точки до точки, задаваемой соответствующим элементом массива lpPoints. Допустимы следующие значения для типов линий:

PT_MOVETO

линия не рисуется, текущая точка перемещается в указанную позицию

PT_LINETO

рисуется отрезок от текущей точки, до указанной; текущая точка перемещается в конечную точку отрезка.

PT_BEZIERTO

рисуется кривая Безье; для задания кривой надо определить подряд три точки типа PT_LINETO: первые две точки -- направляющие, последняя -- конечная; текущая точка будет начальная точка кривой, а после рисования текущая точка переместится в конец нарисованного сегмента.

PT_CLOSEFIGURE

этот флаг может быть объединен со значениями PT_LINETO или PT_BEZIERTO; при его указании фигура будет замкнута проведением отрезка от последней точки нарисованного сегмента до первой точки фигуры (точки типа PT_MOVETO или точки, заданной функцией MoveTo перед вызовом PolyDraw.

Перо

Для проведения линий используется специальный объект GDI, который определяет вид проводимой линии, ее цвет и толщину. По аналогии с обычным рисованием на бумаге такой объект получил название перо (pen). Перо является объектом GDI, следовательно к нему применяются все правила работы с объектами GDI, рассмотренные ранее.

GDI предоставляет возможность использовать одно из трех стандартных перьев или создавать собственные перья, имеющие нужные свойства. Функция GetStockObject позволяет получить стандартное перо; они отличаются только цветом, проводимая ими линия всегда сплошная, шириной 1 единицу устройства (пиксель). Вместо функции GetStockObject можно использовать макрос GetStockPen из windowsx.h. Как и все стандартные объекты GDI эти перья нельзя уничтожать.

HANDLE GetStockObject (nIndex);

HPEN GetStockPen (nIndex); 2

BLACK_PEN

-- черное перо

WHITE_PEN

-- белое перо

NULL_PEN

-- прозрачное перо

Куда больше возможностей предоставляют функции, создающие перья. Две из них -- CreatePen и CreatePenIndirect отличаются только способом передачи параметров. Функция CreatePen получает все характеристики создаваемого пера в виде отдельных параметров, а функция CreatePenIndirect использует структуру LOGPEN, описывающую создаваемое перо. Функционально обе функции тождественны. Эта же структура используется функцией GetObject для получения информации о пере.

HPEN CreatePen (nPenStyle, nWidth, crColor);

HPEN CreatePenIndirect (lpLogPen);

typedef struct tagLOGPEN {

WORD lopnStyle; // стиль пера

POINT lopnWidth; // ширина линии

COLORREF lopnColor; // цвет пера

} LOGPEN;

Стиль пера может быть:

PS_SOLID

сплошная тонкая или толстая линия

PS_DASH

штриховая тонкая линия

PS_DOT

пунктирная тонкая линия

PS_DASHDOT

штрих-пунктирная тонкая линия

PS_DASHDOTDOT

штрих-точка-точка тонкая линия

PS_NULL

(прозрачный)

PS_INSIDEFRAME

сплошная тонкая или толстая линия

Ширина пера задается в логических единицах, причем в случае функции CreatePenIndirect для задания толщины используется структура типа POINT, в которой используется только поле x, а поле y -- нет. Ширина пера задается в логических единицах. Так как логическая единица в общем случае может не совпадать с физической, то для создания тонких перьев (ширина которых равна 1 пикселю или одной строке растра) надо указать требуемую ширину равной 0 -- тогда будет создано перо шириной 1 пиксель. Все прерывистые линии (PS_DOT, PS_DASH, PS_DASHDOT, PS_DASHDOTDOT), шириной больше физической 1 воспроизводятся как PS_SOLID.

Для созданного пера будет назначен ближайший чистый цвет, который может быть воспроизведен данной аппаратурой. В реальных условиях он может отличаться от цвета, заданного вами.

Широкая линия проводится таким образом, что бы ее центр соединял указанные точки. Перо применяется не только для рисования линий, но и для рисования контура фигур. Если при этом используется широкая линия, то может быть удобно, что бы вся линия лежала внутри контура фигуры. Для таких целей предназначен стиль линии PS_INSIDEFRAME. Линии стиля PS_INSIDEFRAME отличаются еще одной особенностью: если ее ширина больше или равна 2 единицам устройства, то эта линия может рисоваться не чистым цветом, а смешанным.

При использовании Win32 API вы можете воспользоваться еще одной функцией для создания перьев:

HPEN ExtCreatePen (dwPenStyle, dwWidth, lpLogBrush, dwStyleCount, lpdwStyle); 1

typedef struct tagLOGBRUSH {

UINT lbStyle;

COLORREF lbColor;

LONG lbHatch;

} LOGBRUSH;

Перья, создаваемые этой функцией делятся на два типа: косметические (cosmetic) и геометрические (geometric). Для описания характеристик пера используется структура LOGBRUSH, обычно применяемая для описания кистей (см. раздел “Кисть”).

Косметические перья создаются, если в параметре dwPenStyle установлен стиль PS_COSMETIC. Они соответствуют тонким сплошным или прерывистым линиям (штриховым, штрих-пунктирным и пунктирным); всегда имеют ширину 1 пиксель (параметр dwWidth должен быть задан 1) и рисуются чистым цветом (цвет задается полем lbColor структуры LOGBRUSH; поле lbStyle обязательно должно быть BS_SOLID, а поле lbHatch не используется). Помимо стиля PS_COSMETIC надо задать один из дополнительных стилей:

Стили PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT, PS_NULL, PS_INSIDEFARME в основном соответствуют уже рассмотренным стилям обычных перьев. (Для косметических ширина всегда равна 1 пикселю).

Стиль PS_ALTERNATE означает, что точки линии будут рисоваться через одну.

Если используется стиль PS_USERSTYLE, то два последних параметра функции ExtCreatePen задают стиль прерывистой линии: параметр lpdwStyle указывает на массив целых чисел, задающих длину штрихов и промежутков между ними; параметр dwStyleCount число записей в этом массиве. Внимание! длина штрихов и промежутков задается не в логических единицах, а в единицах устройства, непосредственно в процессе рисования линии.

Другой вид перьев -- геометрические -- создаются, если в параметре dwPenStyle указан стиль PS_GEOMETRIC. Такие перья могут быть произвольной толщины и цвета, включая узорчатые перья (рисунок на которых задается указанной кистью). Кроме того, при создании геометрических кистей есть возможность задать дополнительные стили. Так, в параметре dwPenStyle вы должны определить стиль PS_GEOMETRIC, стиль линии, стиль оформления окончаний и стиль сопряжения линий.

Стиль линии может быть PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT, PS_NULL, PS_INSIDEFARME или PS_USERSTYLE. Стиль PS_ALTERNATE для геометрических перьев не поддерживается.

Стиль оформления окончаний играет роль для широких линий и может быть PS_ENDCAP_ROUND (конец линии полукруглый), PS_ENDCAP_SQUARE (в виде угла) и PS_ENDCAP_FLAT (прямой).

Стиль сопряжения линий влияет, если несколько последовательно проводимых отрезков сопрягаются под небольшим углом. Он может быть PS_JOIN_BEVEL (линии стыкуются под углом), PS_JOIN_ROUND (сопряжение скругляется) и PS_JOIN_MITER (сопряжение спрямляется). Если используется перо со стилем PS_JOIN_MITER, то дополнительно можно задать предельную величину спрямления сопрягаемых линий с помощью функции

BOOL SetMiterLimit (hDC, eNewLimit, lpeOldLimit); 1

BOOL GetMiterLimit (hDC, lpeOldLimit); 1

Величина спрямления задается относительно ширины линии.

Ширина геометрической линии может быть любой, она задается параметром dwWidth в логических единицах. Параметр lpLogBrush описывает кисть, которая задает цвет и узор линии; кисть может быть однотонной, смешанной, штрихованной или даже созданной по образцу -- зависимому от устройства битмапу. Использование независимых от устройства битмапов в качестве образцов при описании пера недопустимо. О кистях и битмапах см. разделы “Кисть” и “Растровые изображения”.

Как и в случае косметических перьев, параметры dwStyleCount и lpdwStyle определяют стиль штриховки, если задан стиль линии PS_USERSTYLE, иначе они не используются. Однако в отличие от косметического пера, ширина штрихов и промежутков задается в логических единицах.

После использования созданного пера вы должны его уничтожить, причем перед этим он должен быть освобожден из контекста устройства (или весь контекст должен быть освобожден). Перо, как и все объекты GDI, уничтожается с помощью функции:

BOOL DeleteObject (hGDIobj);

BOOL DeletePen (hPen);

Текущая позиция пера

Следующий атрибут контекста устройства, используемый при рисовании линии, называется текущей позицией пера. Этот атрибут используется очень небольшим числом функций, поэтому мы вкратце рассмотрим их всех, даже если они не связаны с рисованием линий.

С первыми тремя функциями мы уже познакомились -- они-то и используются для рисования линий.

DWORD MoveTo (hDC, nX, nY); 0

BOOL MoveToEx (hDC, nX, nY, lpPoint);

BOOL LineTo (hDC, nX, nY);

Помимо них с текущей позицией пера имеют дело функции GetCurrentPosition и GetCurrentPositionEx а также, в некоторых случаях, функции TextOut и ExtTextOut.

DWORD GetCurrentPosition (hDC); 0

BOOL GetCurrentPositionEx (hDC, lpPoint);

Эти функции возвращают позицию пера. Как обычно -- GetCurrentPosition возвращает ее в двойном слове и применятся только в 16ти разрядном Windows API, тогда как функция GetCurrentPositionEx возвращает результат в структуре типа POINT и может применяться как в Windows API, так и в Win32 API.

Две другие функции -- TextOut и ExtTextOut обычно не используют текущую позицию пера, вы должны им отдельно указывать позицию для вывода текста. Однако, иногда может быть удобно перейти в специальный режим привязки текста TA_UPDATECP (см. функцию SetTextAlign), при котором текст будет выводиться от текущей позиции, а после вывода текста текущая позиция переместится в конец выведенного фрагмента.

Цвет фона и режим заполнения фона

Еще один используемый атрибут контекста устройства -- цвет фона. Это не тот цвет, которым закрашивается фон окна, хотя он может и совпадать с ним. Фон окна закрашивается не текущим цветом фона, а кистью, назначенной окну при регистрации класса. Цвет фона и режим заполнения фона используются:

функциями для рисования линий -- для заполнения промежутков между штрихами прерывистой линии

функциями вывода текста -- для заполнения пространства под символами текста.

функциями, применяющими кисть -- для заполнения фона между линиями штрихованных кистей.

Рисунок 5. Рисование прерывистых линий в разных режимах заполнения фона.

Для задания цвета фона и для выяснения текущего цвета вы можете воспользоваться функциями

COLORREF SetBkColor (hDC, crColor);

COLORREF GetBkColor (hDC);

Функции возвращают используемый ранее цвет фона. Аналогично перу, GDI будет использовать ближайший чистый цвет в качестве цвета фона.

В некоторых случаях бывает удобно проводить пунктирные и штрих-пунктирные линии так, что бы в промежутках был виден прежний фон (прежнее изображение), а не закрашивать их цветом фона. Для этого вы должны изменить режим заполнения фона. Для это предназначены функции:

int SetBkMode (hDC, nBkMode);

int GetBkMode (hDC);

GDI поддерживает два разных режима заполнения фона; один из них называется OPAQUE -- это режим по умолчанию. В режиме OPAQUE промежутки заполняются текущим цветом фона, а в другом режиме, называемом TRANSPARENT, фон в промежутках не изменяется.

Режим рисования

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

Атрибут режим рисования задает правила, по которым GDI переносит информацию из одной битовой последовательности на другую. Так, помимо самого очевидного копирования возможны операции инверсии как уже имеющегося изображения, так и рисуемого, объединение с помощью различных битовых операций И (and), ИЛИ (or), ИСКЛЮЧАЮЩЕЕ ИЛИ (xor).

При рассмотрении процесса переноса изображения мы будем исходить из предположения монохромного устройства вывода, так как анализ процесса рисования на цветном устройстве выглядит громоздко. Говоря о монохромном устройстве мы будем обозначать светлую точку будем битом со значением 1, а для темную точку -- 0.

При рисовании мы можем условно рассматривать три разные битовые последовательности:

исходное изображение, содержащее рисуемый объект, в документации называется pen (почему-то считается, что рисуется именно линия текущим карандашом -- отсюда название -- но, вообще говоря, режим рисования применяется для всех операций вывода графических примитивов -- линий, эллипсов, многоугольников, текста и пр.);

контекст устройства, содержащий нарисованный ранее образ (хотя бы просто закрашенный фон), в документации называется destination;

результат -- то изображение, которое будет находиться на контексте устройства после рисования;

Применительно к этим трем битовым последовательностям говорят о двоичной растровой операции (binary raster operation, ROP2), так как в формировании результата участвуют две исходных битовых последовательности.

Режим рисования задает операцию над битами обеих последовательностей, выполняемую в процессе переноса изображения. Всего возможно 16 различных режимов рисования:

Перо (Pen) P

1 1 0 0

Выполняемая

Режим рисования

Имеющееся изображение (Destination) D

1 0 1 0

операция

0 0 0 0

0

0 R2_BLACK

0 0 0 1

~ (P|D)

1 R2_NOTMERGEPEN

0 0 1 0

(~P)&D

2 R2_MASKNOTPEN

0 0 1 1

~P

3 R2_NOTCOPYPEN

0 1 0 0

P& (~D)

4 R2_MASKPENNOT

0 1 0 1

~D

5 R2_NOT

Повторное рисование восстанавливает фон

0 1 1 0

P^D

6 R2_XORPEN

0 1 1 1

~ (P&D)

7 R2_NOTMASKPEN

1 0 0 0

P&D

8 R2_MASKPEN

1 0 0 1

~ (P^D)

9 R2_NOTXORPEN

Прежнее изображение не меняется

1 0 1 0

D

10 R2_NOP

1 0 1 1

(~P)|D

11 R2_MERGENOTPEN

Режим рисования по умолчанию

1 1 0 0

P

12 R2_COPYPEN

1 1 0 1

P| (~D)

13 R2_MERGEPENNOT

1 1 1 0

P|D

14 R2_MERGEPEN

1 1 1 1

1

15 R2_WHITE

Так, например, по умолчанию используется операция копирования исходного изображения на контекст устройства (называемая R2_COPYPEN), довольно часто применяется операция исключающее или (R2_XORPEN) между пером и существующим изображением на контексте.

Если монохроматические переносимое изображение и уже имеющееся рассматривать как битовые последовательности, то возможны 4 случая:

оба изображения, переносимое (pen) и имеющееся (destination), содержат светлые точки

переносимое изображение (pen) содержит светлую точку, а имеющееся (destination) -- темную

переносимое изображение (pen) содержит темную точку, а имеющееся (destination) -- светлую

оба изображения, переносимое (pen) и имеющееся (destination), содержат темные точки

Говоря в терминах битов может понадобиться комбинировать 1 с 1, 1 с 0, 0 с 1 и 0 с 0. Эти четыре варианта перечислены во втором столбце таблицы в заголовке. В строчках ниже дается ожидаемый результат во всех четырех случаях.

Например, если в результате комбинирования светлой со светлой должна получиться светлая точка (1 и 1 дает 1), а в остальных случаях -- темная (1 и 0, 0 и 1, а также 0 и 0 дают 0), то в таблице эта операция будет обозначена как 1 0 0 0 -- R2_MASKPEN.

Вы можете установить желаемый режим рисования, или узнать текущий с помощью функций

int SetROP2 (hDC, nIndex);

int GetROP2 (hDC);

В описании этих функций можно также найти символические имена всех 16 режимов и их краткое описание. Однако, следуя приводимому в документации описанию, найти нужную операцию может быть затруднительно (обычно там не приводятся результаты выполнения операций, только названия и обозначения). В этом случае вы можете получать нужный номер растровой операции из этой таблички, даже вы вообще можете обойтись без символических имен, просто рассматривая битовую последовательность в табличке как номер режима. Этим правилом можно пользоваться, если порядок четырех возможных комбинаций соответствует приведенному в таблице и в примере.

Например, вы хотите выбрать такой режим, что бы изображение получало светлую точку только в том случае, когда и рисуемая точка и точка имеющегося фона имеют темный цвет, или когда точка линии -- светлая, а фона -- темная; во всех остальных случаях должна получиться темная точка.

Рисунок 6. Получение номера растровой операции.

Направление рисования дуг

Для задания дуги, которую вы хотите нарисовать необходимо определить эллипс, дугу которого вы собираетесь нарисовать, а также начальную и конечную точки дуги. Но вот проблема -- от начальной до конечной точки можно провести дугу в двух разных направлениях, так что приходится дополнительно определять, в каком именно направлении дуга будет нарисована. Обычно принято, что дуга рисуется против хода часовой стрелки.

Вы можете при необходимости узнать или изменить направление рисования дуг с помощью функций:

int GetArcDirection (hDC);

int SetArcDirection (hDC, nIndex);

Допустимыми являются AD_COUNTERCLOCKWISE -- рисование против хода часовой стрелки (принято по умолчанию) и AD_CLOCKWISE -- по ходу часовой стрелки.

Внимание! Эти две функции не работают в случае расширенного режима задания координат (см. функцию SetGraphicsMode 1, GM_ADVANCED) -- в этом случае дуги всегда рисуются против хода часовой стрелки.

Дополнительные средства для рисования линий

Windows содержит еще одну функцию, которая применяется для рисования линий. Она предназначена для последовательного вычисления координат точек, принадлежащих линии, и выполнения над этими точками какой-либо операции, определенной пользователем. Фактически эта функция для каждой точки рисуемой линии вызывает указанную пользователем процедуру. Любопытно, что сама эта функция никак не взаимодействует с контекстом устройства, она выполняет только математические операции, вычисляя все промежуточные точки линии.

void LineDDA (nXStart, nYStart, nXEnd, nYEnd, lpfnDdaPrc, lParam);

nXStart, nYStart -- определяют первую точку линии

nXEnd, nYEnd -- определяют последнюю точку линии

lpfnDdaPrc -- указатель на процедуру типа LINEDDAPROC

lParam -- данные, передаваемые пользователем процедуре LINEDDAPROC

Вызываемая процедура LINEDDAPROC имеет следующий вид:

void CALLBACK LineDDAproc (nX, nY, lParam) {

// ...}

Процедура LineDDAproc получает координаты точки, которую надо нарисовать и данные, переданные пользователем.

Координаты первой и последней точек задаются в произвольных единицах, так как их использование определяется не процедурой LineDDA, а процедурой LineDDAproc, разрабатываемой вами. Какие координаты вам удобнее -- такие и используйте. Адрес процедуры lpfnDdaPrc в случае Windows API является адресом, возвращаемом функцией MakeProcInstance, но не адресом самой процедуры (об этом подробнее -- в разделе «диспетчер памяти»). Данные, передаваемые пользователем, (lParam) являются двойным словом. В документации утверждается, что это дальний указатель на данные, хотя это некорректное утверждение. Часто параметр в виде двойного слова используется для задания адреса каких-либо данных (особенно, если данные занимают больше двух слов), однако реально там может удерживаться произвольное 32х разрядное число. Более того, в прототипе функции он описан именно как long.

Рисование заполненных фигур

Следующая группа функций предназначена для отображения заполненных фигур. К таким фигурам относятся прямоугольники, прямоугольники со скругленными краями, эллипсы, сектора, дуги, стянутые хордой и многоугольники. Условно можно представить себе рисование заполненных фигур как процесс, состоящий из двух этапов -- рисование контура текущим пером и заполнение фона. При рисовании контура справедливы все замечания, сделанные при обсуждении рисования линий. Если вам не надо рисовать контур, то выберите в контекст устройства прозрачный карандаш (функция GetStockObject или макрос GetStockPen, NULL_PEN). При заполнении фона рисуемой фигуры используются как уже рассмотренные атрибуты GDI, так и несколько новых. Естественно, что перед рисованием нужной вам фигуры вы должны установить требуемые значения атрибутов контекста устройства.


Подобные документы

  • Разработка графического редактора для рисования двухмерной и трехмерной графики, используя язык программирования Java и интерфейсы прикладного программирования Java 2D и Java 3D. Создание графического редактора 3D Paint. Основные методы класса Graphics.

    курсовая работа [197,5 K], добавлен 19.11.2009

  • Сущность, задачи и особенности объектно-ориентированного программирования. Создание и редактирование графических файлов при помощи различных инструментов рисования. Основные требования к аппаратному и программному обеспечению. Руководство пользователя.

    курсовая работа [270,9 K], добавлен 09.03.2009

  • Структура организации графического интерфейса, объявление и создание слушателей событий с помощью анонимных классов. Представление данных для таблицы – класс AbstractTableModel. Визуализация ячеек таблицы. Два основных типа потоков ввода-вывода в Java.

    лекция [685,3 K], добавлен 01.05.2014

  • Разработка графического интерфейса для ввода начальных значений, отображения результатов и тестирования методов собственного класса на языке программирования С++. Подсветка цветом выбранных операндов в процессе их инициализации и вывода на дисплей.

    курсовая работа [234,6 K], добавлен 27.12.2014

  • Изучение особенностей растровых и векторных графических редакторов. Создание графического редактора: выбор языка программирования, разработка структуры программы и алгоритма работы. Описание интерфейса программы. Руководство программиста и пользователя.

    курсовая работа [1,3 M], добавлен 28.07.2013

  • Растровая и векторная графика. Растровые графические редакторы. Масштабирование растрового изображения. Средства хранения высокоточных графических объектов. Изменение масштаба без потери качества и практически без увеличения размеров исходного файла.

    презентация [652,8 K], добавлен 11.03.2015

  • Растровая графика, составление графических изображений из отдельных точек (пикселей). Растровые графические редакторы. Векторная графика - построение изображения из простых объектов. Достоинства, недостатки и применение растровой и векторной графики.

    презентация [7,8 K], добавлен 06.01.2014

  • Определение понятия "видеокарта". Рассмотрение режима работы устройства по преобразованию цифрового сигнала в аналоговый электрический. Изучение особенностей изображения графических и текстовых знаков. Описание графического ускорителя и акселератора.

    презентация [1,2 M], добавлен 20.12.2015

  • Методы вывода графических примитивов в программе Delphi. Основные методы, объявленные в классе TCanvas. Использование объектов Brush, Pen, Front. Примеры применения функции Round Rect. Отличия способов рисования прямоугольника Polyline и Polygon.

    курсовая работа [834,1 K], добавлен 17.09.2014

  • Создание с помощью графического редактора логотипа и баннера для образовательного сайта "Областные математические олимпиады". Типы логотипов, баннер как графический элемент страницы сайта. Обзор инструментов графического редактора Adobe Illustrator.

    курсовая работа [2,9 M], добавлен 08.02.2014

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.