2.1. Получение и освобождение контекста отображения
2.2. Выбор режима отображения
2.3. Рисование геометрических фигур
2.4. Приложение LINER
2.5. Области
2.6. Приложение REGIONS
2.7. Сохранение и восстановление контекста отображения
2.8. Приложение DASHLINE
В этой главе вы научитесь получать контекст отображения и контекст
устройства , изменять его атрибуты и рисовать простейшие графические
изображения на экране монитора. Вопросы, связанные с использованием
цвета, цветовых палитр, вывода текста и графических изображений
bitmap, а также печати на принтере будут рассмотрены в следующих
главах нашей книги.
Как правило, приложения выполняют всю работу по рисованию во время
обработки сообщения WM_PAINT , хотя часто требуется рисовать и
во время обработки других сообщений. В любом случае приложение
должно придерживаться следующей последовательности действий:
- получение или создание контекста отображения;
- установка необходимых атрибутов в контексте отображения;
- выполнение операций рисования;
- освобождение или удаление контекста отображения.
Последнее действие (освобождение или удаление контекста отображения)
должно быть обязательно выполнено. Самый простой способ полностью
нарушить работоспособность Windows - забыть освободить полученный
контекст отображения или удалить созданный контекст отображения
или устройства.
Так как контекст отображения - критический ресурс, его необходимо
освобождать сразу, как только в нем отпадет необходимость. Операционная
система Windows выполняет кеширование обычного контекста отображения
(есть и необычные контексты отображения, но об этом позже), причем
кешируются только пять контекстов. Если Windows не может удовлетворить
запрос какого-либо приложения на выделение контекста отображения,
вся операционная система окажется в критическом состоянии, единственным
выходом из которого будет полный перезапуск Windows.
Среди всех атрибутов контекста отображения, описанных в первой
главе, особое место занимает режим отображения, влияющий на систему
координат и, соответственно, на работу практически всех функций
рисования. Поэтому необходимо уделить особое внимание вопросам
использования режимов отображения и систем координат.
Однако прежде всего необходимо научиться получать и освобождать
контекст отображения.
Способы получения (и, соответственно, освобождения) контекста
отображения разные для контекстов разного типа. Можно выделить
следующие типы контекста отображения:
- общий контекст отображения (common display context);
- контекст отображения для класса окна (class display context);
- личный контекст отображения (private display context);
- родительский контекст отображения (parent display context);
- контекст отображения для окна (window display context);
- контекст физического устройства (device context);
- информационный контекст (information context);
- контекст для памяти (memory device context);
- контекст для метафайла (metafile context).
Каждый из перечисленных выше контекстов имеет свои особенности
и свое назначение.
Общий контекст отображения
Этот контекст используется чаще всего и поэтому для ускорения
доступа к нему Windows использует кеширование (как мы уже говорили,
размер кеша достаточен для хранения только пяти контекстов отображения).
Для получения общего контекста отображения приложение должно вызвать
функцию BeginPaint (при обработке сообщения WM_PAINT ) или GetDC
(при обработке других сообщений). При этом перед регистрацией
класса окна в поле стиля класса окна в структуре WNDCLASS не должны
использоваться значения CS_OWNDC , CS_PARENTDC или CS_CLASSDC
:
wc.style = 0;
Функция BeginPaint возвращает контекст отображения для окна hwnd:
HDC WINAPI BeginPaint(HWND hwnd, PAINTSTRUCT FAR* lpps);
Перед этим она подготавливает указанное окно для рисования, заполняя
структуру типа PAINTSTRUCT (адрес которой передается через параметр
lpps) информацией, которую можно использовать в процессе рисования.
Структура PAINTSTRUCT и указатели на нее (различных типов) описаны
в файле windows.h:
typedef struct tagPAINTSTRUCT
{
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[16];
} PAINTSTRUCT;
typedef PAINTSTRUCT* PPAINTSTRUCT;
typedef PAINTSTRUCT NEAR* NPPAINTSTRUCT;
typedef PAINTSTRUCT FAR* LPPAINTSTRUCT;
Рассмотрим назначение отдельных полей структуры PAINTSTRUCT.
Поле hdc после возврата из функции будет содержать идентификатор
полученного контекста отображения, который должен передаваться
в качестве параметра функциям интерфейса GDI, выполняющим рисование.
Можно использовать также значение идентификатора контекста, возвращенное
функцией BeginPaint, так как эти значения одинаковые.
Анализируя содержимое поля fErase, приложение может определить,
нужно ли перерисовывать фон окна. Если в этом поле находится значение
TRUE, фон окна должен быть перерисован. Такая необходимость может
возникнуть в том случае, если в классе, на базе которого создано
окно, при регистрации не была выбрана кисть для закрашивания фона
(поле hbrBackground структуры WNDCLASS).
Поле rcPaint, которое представляет собой структуру типа RECT,
содержит координаты верхнего левого и правого нижнего угла прямоугольника,
внутри которого нужно рисовать. Напомним вам формат структуры
RECT , описанной в файле windows.h:
typedef struct tagRECT
{
int left;
int top;
int right;
int bottom;
} RECT;
Мы уже говорили вам в 11 томе "Библиотеки системного программиста",
что при обработке сообщения WM_PAINT приложение должно суметь
перерисовать все окно или любую его часть. Сообщение WM_PAINT
может попасть в функцию окна в том случае, если все окно или его
часть требуют перерисовки. Поле rcPaint в структуре PAINTSTRUCT
содержит координаты прямоугольной области, расположенной в окне
и требующей перерисовки.
Остальные поля зарезервированы для Windows и не используются приложениями.
Контекст отображения, полученный при помощи функции BeginPaint,
необходимо освободить перед завершением обработки сообщения WM_PAINT,
вызвав функцию EndPaint :
void WINAPI EndPaint(HWND hwnd, const PAINTSTRUCT FAR* lpps);
Функции EndPaint передаются те же параметры, что и функции BeginPaint.
Обычно обработчик сообщения WM_PAINT выглядит следующим образом:
PAINTSTRUCT ps;
HDC hdc;
........
case WM_PAINT:
{
// Получаем контекст отображения
hdc = BeginPaint(hwnd, &ps);
// После получения контекста отображения
// можно вызывать функции GDI
TextOut(hdc, 0, 0, (LPSTR)"String", 6);
.
.
// Освобождаем контекст отображения
EndPaint(hwnd, &ps);
break;
}
Подобный фрагмент кода вы можете найти в приложениях, описанных
в одном из предыдущих томов "Библиотеки системного программиста".
Функции BeginPaint и EndPaint можно использовать только внутри
обработчика сообщения WM_PAINT. Если же приложению требуется рисовать
во время обработки других сообщений, оно должно получить контекст
отображения с помощью функции GetDC . После завершения процедуры
рисования перед выходом из обработчика сообщения следует освободить
полученный контекст отображения, вызвав функцию ReleaseDC .
Функция GetDC возвращает контекст отображения для окна с идентификатором
hwnd:
HDC WINAPI GetDC(HWND hwnd);
Полученный таким образом контекст отображения можно использовать
для рисования во внутренней области окна (window client region).
Функция ReleaseDC освобождает контекст отображения hdc, полученный
для окна hwnd:
int WINAPI ReleaseDC(HWND hwnd, HDC hdc);
Мы еще раз обращаем ваше внимание на необходимость своевременного
освобождения общего контекста отображения.
Каждый раз, когда приложение получает общий контекст отображения,
его атрибуты принимают значения по умолчанию, перечисленные нами
ранее. Если перед выполнением рисования приложение изменит атрибуты
контекста отображения, вызвав соответствующие функции GDI, в следующий
раз при получении общего контекста отображения эти атрибуты снова
примут значения по умолчанию. Поэтому установка атрибутов должна
выполняться каждый раз после получения общего контекста отображения.
Такая процедура отнимает дополнительное время, но она необходима
при использовании контекста отображения этого типа.
Контекст отображения для класса окна
Общий контекст отображения , описанный нами в предыдущем разделе,
кешируется операционной системой Windows для ускорения доступа
к нему. Однако вы можете создать такой контекст отображения, который
хранится отдельно в единственном экземпляре и используется всеми
окнами, созданными на базе класса окна. При регистрации такого
класса окна вы должны указать стиль CS_CLASSDC :
wc.style = CS_CLASSDC;
Все окна, созданные на базе класса, имеющего стиль CS_CLASSDC,
будут использовать один общий контекст отображения.
В отличие от общего контекста отображения, приложения, однажды
получив контекст отображения для класса окна, могут не освобождать
его. То есть для контекста этого типа после функций BeginPaint
и GetDC можно не вызывать функции EndPaint и ReleaseDC. Если же
приложение вызовет функцию EndPaint или ReleaseDC, они не будут
ничего делать и сразу вернут управление. Для уменьшения вероятности
ошибки мы рекомендуем вам всегда освобождать контекст отображения,
даже если это и не требуется для данного типа контекста.
Несмотря на то, что для всех окон, созданных на базе класса стиля
CS_CLASSDC, создается один контекст отображения, не следует думать,
что приложение, однажды получив этот контекст, не должно получать
его вновь при очередном вызове обработчика сообщения, выполняющего
рисование.
Дело в том, что при получении контекста отображения для окна в
нем устанавливаются атрибуты области ограничения и начало системы
физических координат устройства отображения. Если на базе нашего
класса создано несколько окон, при получении ими контекста отображения
эти атрибуты "настраиваются" на окно, получившее контекст
отображения. Но если на базе класса стиля CS_CLASSDC приложение
создало только одно окно, оно может получить контекст отображения
для класса окна один раз и не освобождать его.
Зачем используется контекст отображения класса окна?
Вы можете использовать его в тех случаях, когда по соображениям
повышения производительности нежелательно выполнять настройку
многочисленных атрибутов контекста отображения после каждого вызова
функции BeginPaint или EndPaint. Эту настройку можно выполнить
только один раз. Каждый раз, когда функция окна получает контекст
отображения класса окна, в нем выполняется настройка только двух
атрибутов - области ограничения и начала системы физических координат
устройства вывода. Остальные атрибуты остаются без изменений и,
следовательно, не требуют повторной настройки.
Личный контекст отображения
Указав в стиле класса окна значение CS_OWNDC , можно добиться
того, что для каждого окна, созданного на базе такого класса,
Windows создаст отдельную структуру контекста отображения:
wc.style = CS_OWNDC;
Личный контекст отображения можно, получив один раз, никогда не
освобождать. Вы можете один раз настроить атрибуты контекста отображения
сразу после получения самого контекста и использовать полученный
контекст без изменений до завершения работы приложения.
Однако не будет ошибкой, если приложение будет использовать личный
контекст отображения как общий, то есть каждый раз при обработке
сообщения WM_PAINT (или другого сообщения, обработчик которого
занимается рисованием) оно будет получать контекст и затем отдавать
его. Соответствующие функции (BeginPaint, EndPaint, GetDC, ReleaseDC)
будут возвращать управление, не выполняя никаких действий.
Личный контекст проще в использовании, так как его можно получать
и настраивать только один раз, однако оперативная память будет
расходоваться менее экономно.
Родительский контекст отображения
Родительский контекст отображения используется для дочерних окон.
Он позволяет дочерним окнам "унаследовать" атрибуты
контекста отображения у родительского окна, что во многих случаях
упрощает процедуру настройки этих атрибутов. Например, дочернее
окно может использовать для вывода текста тот же шрифт и цвета,
что и родительское окно.
Для использования родительского контекста отображения в классе,
на базе которого создается дочернее окно, перед регистрацией необходимо
указать стиль CS_PARENTDC :
wc.style = CS_PARENTDC;
Контекст отображения для окна
Все описанные выше контексты отображения позволяют рисовать только
во внутренней области окна (client region). С помощью функции
GetWindowDC приложение может получить контекст отображения для
окна , позволяющий рисовать в любом месте окна (в области заголовка
окна, в области системного меню, рамки окна, кнопок изменения
размера и т. п.).
Контекст отображения, полученный для окна, используется аналогично
общему контексту отображения. После получения контекста его атрибуты
принимают значения по умолчанию. Приложение обязано освобождать
этот контекст сразу после использования, вызывая функцию ReleaseDC.
Особенностью данного контекста является то, что в нем выбрана
система координат, начало которой находится в левом верхнем углу
окна (всего окна, а не его внутренней области).
Такой контекст может использоваться при необходимости заменить
стандартные элементы окна (заголовок, полосы просмотра и т. п.)
на собственные, или если приложение желает нарисовать что-нибудь
в области заголовка или рамки.
Контекст физического устройства
Вывод изображений на такое устройство, как принтер, может выполняться
с использованием тех же приемов, что и вывод в окно приложения.
Прежде всего необходимо получить контекст устройства . Затем можно
вызывать функции GDI, выполняющие рисование, передавая им идентификатор
полученного контекста в качестве параметра.
В отличие от контекста отображения, контекст физического устройства
не получается, а создается, для чего используется функция CreateDC
:
HDC WINAPI CreateDC(
LPCSTR lpszDriver, // имя драйвера
LPCSTR lpszDevice, // имя устройства
LPCSTR lpszOutput, // имя файла или порта вывода
const void FAR* lpvInitData); // данные для инициализации
Параметр lpszDriver является указателем на строку символов, содержащую
имя драйвера, обслуживающего физическое устройство. Имя драйвера
совпадает с именем файла *.drv, содержащего сам драйвер и расположенного
в системном каталоге Windows.
Имя устройства lpszDevice - это название самого устройства, описанное,
например, в файле win.ini в разделе [devices].
Параметр lpszOutput указывает на структуру данных типа DEVMODE,
используемую при инициализации устройства вывода. Если при работе
с устройством нужно использовать параметры, установленные при
помощи приложения Control Panel, параметр lpszOutput следует указать
как NULL.
Более подробно вопросы работы с принтером будут рассмотрены в
отдельной главе этого тома.
В приведенном ниже примере создается контекст устройства для лазерного
принтера HP Laserjet III, подключенного к порту LPT1:, причем
в системном каталоге Windows для этого принтера установлен драйвер
hppcl5a.drv:
hdc = CreateDC("hppcl5a", "HP LaserJet III", "LPT1:", NULL);
Аналогично, для принтера Epson FX-850, подключенного к порту LPT2:,
и работающему через драйвер epson9.drv:
hdc = CreateDC("epson9", "Epson FX-850", "LPT2:", NULL);
Созданный при помощи функции CreateDC контекст устройства следует
удалить (но не освободить), вызвав функцию DeleteDC:
BOOL WINAPI DeleteDC(HDC hdc);
Эта функция возвращает TRUE при нормальном завершении и FALSE
при возникновении ошибки.
Контекст для устройства DISPLAY
В некоторых случаях требуется получить контекст отображения, позволяющий
приложению рисовать в любом месте экрана дисплея. Такой контекст
можно создать при помощи функции CreateDC, указав в качестве имени
драйвера строку "DISPLAY ", а в качестве остальных параметров
- значение NULL:
hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
В данном случае будет создан контекст для видеомонитора, с помощью
которого приложение может рисовать в любом месте экрана. Начало
системы координат, выбранной в данный контекст, располагается
в верхнем левом углу экрана видеомонитора.
После использования созданный таким образом контекст отображения
следует удалить, вызвав функцию DeleteDC.
Есть еще два способа получения контекста для экрана.
Приложение может получить контекст отображения для всего экрана
при помощи функции GetDC, указав в качестве параметра значение
NULL:
hdc = GetDC(NULL);
Полученный таким образом контекст следует освободить после использования
при помощи функции ReleaseDC, передав ей вместо идентификатора
окна значение NULL:
ReleaseDC(NULL, hdc);
Еще один способ связан с использованием функции GetDCEx, описание
которой будет приведено ниже.
Информационный контекст
Если приложению необходимо получить информацию об устройстве вывода
(например, с помощью функции GetDeviceCaps, рассмотренной нами
в 11 томе "Библиотеки системного программиста"), оно
может создать вместо обычного информационный контекст . Информационный
контекст нельзя использовать для рисования, однако он занимает
меньше места в памяти.
Информационный контекст создается при помощи функции CreateIC
, аналогичной по своим параметрам функции CreateDC:
HDC WINAPI CreateIC(
LPCSTR lpszDriver, // имя драйвера
LPCSTR lpszDevice, // имя устройства
LPCSTR lpszOutput, // имя файла или порта вывода
const void FAR* lpvInitData); // данные для инициализации
После использования информационный контекст следует удалить, вызвав
функцию DeleteDC.
Контекст для памяти
В работе с битовыми изображениями bitmap часто используется такое
"устройство вывода", как оперативная память. Приложение
может полностью подготовить изображение в оперативной памяти,
получив контекст для памяти , и затем быстро вывести готовое изображение
на экран. Этот способ во многих случаях работает намного быстрее
и приятнее для пользователя, чем формирование изображения непосредственно
на экране.
Контекст для памяти создается совместимым с тем контекстом отображения,
в котором будет выполняться вывод на физическое устройство. Для
создания совместимого контекста используется функция CreateCompatibleDC
:
HDC WINAPI CreateCompatibleDC(HDC hdc);
Созданный таким образом контекст памяти удаляется при помощи функции
DeleteDC.
Использование контекста памяти будет подробно описано в главе,
посвященной битовым изображениям bitmap.
Контекст для метафайла
Контекст для метафайла позволяет записывать команды GDI в файл
и затем проигрывать такой файл на физическом устройстве вывода.
Файл может находиться в памяти или на диске, в последнем случае
его можно использовать для переноса графического изображения в
другое приложение.
Для создания контекста метефайла используется функция CreateMetaFile
:
HDC WINAPI CreateMetaFile(LPCSTR lpszFileName);
Параметр lpszFileName должен указывать на строку, содержащую путь
к имени файла, в который будут записаны команды GDI, или NULL.
В последнем случае создается метафайл в оперативной памяти.
После выполнения рисования в контексте метафайла следует закрыть
метафайл, вызвав функцию CloseMetaFile :
HMETAFILE WINAPI CloseMetaFile(HDC hdc);
Эта функция закрывает метафайл для контекста hdc и возвращает
идентификатор метафайла. Идентификатор закрытого метафайла использовать
нельзя, так как он не содержит никакой полезной информации.
Что можно сделать с полученным идентификатором метафайла?
Можно скопировать метафайл в обычный дисковый файл, вызвав функцию
CopyMetaFile :
HMETAFILE WINAPI CopyMetaFile(HMETAFILE hmf,
LPCSTR lpszFileName);
Параметр hmf определяет метафайл, параметр lpszFileName содержит
путь к имени файла, в который будет записан метафайл .
Можно проиграть метафайл в контексте отображения или контексте
устройства, вызвав функцию PlayMetaFile :
BOOL WINAPI PlayMetaFile(HDC hdc, HMETAFILE hmf);
Наконец, при помощи функции DeleteMetaFile можно удалить метафайл:
BOOL WINAPI DeleteMetaFile(HMETAFILE hmf);
Удаление метафайла с помощью функции DeleteMetaFile делает недействительным
идентификатор метафайла hmf и освобождает оперативную память,
занятую метафайлом. Если метафайл был создан как обычный дисковый
файл, функция DeleteMetaFile не удаляет его с диска.
Для того чтобы воспользоваться метафайлом, хранящимся в виде дискового
файла, его следует загрузить при помощи функции GetMetaFile ,
указав ей в качестве единственного параметра путь к соответствующему
файлу:
HMETAFILE WINAPI GetMetaFile(LPCSTR lpszFileName);
Функция GetDCEx
В программном интерфейсе операционной системы Windows версии 3.1
появилась функция GetDCEx , предоставляющая расширенные возможности
для получения контекста отображения:
HDC WINAPI GetDCEx(register HWND hwnd,
HRGN hrgnClip, DWORD flags);
Функция возвращает идентификатор полученного контекста отображения
или NULL при ошибке.
Параметр hwnd задает идентификатор окна, для которого необходимо
получить контекст отображения.
С помощью параметра hrgnClip можно определить область ограничения
вывода. Эта область может иметь произвольную форму и являться
комбинацией нескольких областей ограничения. Использование областей
ограничения будет подробно описано дальше в этой главе.
Параметр flags определяет способ, которым будет образован контекст
отображения. Этот параметр можно указывать как логическую комбинацию
следующих значений:
Константа | Описание |
DCX_WINDOW | Функция возвращает контекст отображения, позволяющий рисовать во всем окне, а не только в его внутренней области
|
DCX_CACHE | Функция получает общий контекст отображения из кеша Windows, даже если окно создано на базе класса стиля CS_OWNDC или CS_CLASSDC
|
DCX_CLIPCHILDREN | Видимые области всех дочерних окон, расположенных ниже окна hwnd, исключаются из области отображения
|
DCX_CLIPSIBLINGS | Видимые области всех окон-братьев (окон, имеющих общих родителей), расположенных выше окна hwnd, исключаются из области отображения
|
DCX_PARENTCLIP | Для отображения используется вся видимая область родительского окна, даже если родительское окно создано с использованием стилей WS_CLIPCHILDREN и WS_PARENTDC. Начало координат устанавливается в левый верхний угол окна hwnd
|
DCX_EXCLUDERGN | Если указан этот флаг, при выводе будет использована область ограничения, заданная параметром hrgnClip
|
DCX_INTERSECTRGN | Используется пересечение области ограничения, заданной параметром hrgnClip, и видимой области полученного контекста отображения
|
DCX_LOCKWINDOWUPDATE | Этот флаг разрешает рисование в окне, заблокированном для рисования функцией LockWindowUpdate . Флаг можно использовать при необходимости рисовать, например, рамку, выделяющую произвольную область экрана
|
Контекст отображения, полученный функцией GetDCEx, следует освободить
после использования при помощи функции ReleaseDC.
Напомним, что режим отображения - это атрибут контекста отображения,
влияющий на используемую функциями GDI систему координат. Для
обеспечения независимости приложений от аппаратного обеспечения
приложения Windows работают с логическими координатами, которые
отображаются в физические. Приложения Windows (в отличие от программ
MS-DOS) могут не знать номер используемого видеорежима и соответствующее
ему разрешение по вертикали и горизонтали в пикселах, определяя
размеры элементов формируемого изображения в миллиметрах или дюймах.
Хотя в качестве единицы измерения можно использовать и пиксел,
если выбрать соответствующий режим отображения.
Из уроков геометрии в школе и институте вы знаете, что существуют
различные системы координат, каждая из которых удобна в том или
ином случае. Мы не будем описывать все возможные системы координат,
ограничившись доступными в Windows версии 3.1 (в операционной
системе Windows NT набор систем координат немного расширен).
Изучение режимов отображения Windows версии 3.1 мы начнем с определения
основных понятий и терминов, имеющих отношение к системам координат
и преобразованию логических координат в физические.
Основные определения
Прежде всего необходимо определить понятия "физические координаты
" и "логические координаты ".
Физические координаты, как это следует из названия, имеют непосредственное
отношение к физическому устройству вывода. В качестве единицы
измерения длины в системе физических координат всегда используется
пиксел. Если устройством вывода является экран монитора, физические
координаты обычно называют экранными координатами.
Логические координаты передаются функциям GDI, выполняющим рисование
фигур или вывод текста. Используемые единицы измерения зависят
от режима отображения.
При отображении GDI преобразует логические координаты в физические.
Способ преобразования зависит от режима отображения и других атрибутов
контекста отображения, таких как расположение начала системы координат
для окна, расположение начала системы физических координат, масштаб
осей для окна и масштаб осей физических координат.
Физическая система координат
На рис. 2.1 показана физическая система координат для экрана видеомонитора.
Рис. 2.1. Физическая система координат для экрана видеомонитора
Начало этой системы координат располагается в левом верхнем углу
экрана. Ось X направлена слева направо, ось Y - сверху вниз. В
качестве единицы длины в данной системе координат используется
пиксел.
Для того чтобы определить физическое разрешение устройства вывода
(например, размер экрана в пикселах по вертикали и горизонтали),
следует использовать функцию GetDeviceCaps , которую мы рассмотрели
в 11 томе "Библиотеки системного программиста". Если
передать в качестве второго параметра этой функции значения VERTRES
и HORZRES , она в любом режиме отображения вернет, соответственно,
размер экрана в пикселах по вертикали и по горизонтали. Параметр
hdc должен указывать информационный контекст или контекст отображения,
связанный с экраном монитора:
HDC hdc;
int iVertRes, iHorzRes;
hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
iVertRes = GetDeviceCaps(hdc, VERTRES);
iHorzRes = GetDeviceCaps(hdc, HORZRES);
DeleteDC(hdc);
Физическая система координат "привязана" к физическому
устройству вывода, поэтому при ее использовании для вывода изображения
следует учитывать особенности видеоконтроллера. В 11 томе "Библиотеки
системного программиста" в разделе, посвященном метрикам
операционной системы Windows, мы подробно рассказали об использовании
функции GetDeviceCaps для исследования пространственных характеристик
монитора. Для удобства мы воспроизведем приведенную в этом томе
таблицу некоторых метрик для видеомониторов различных типов.
Параметр функции GetDeviceCaps | CGA
| EGA | VGA
| SVGA 800 x 600 |
8514/A | SVGA 1024 x 768
|
HORZRES | 640
| 640 | 640
| 800 | 1024
| 1024 |
VERTRES | 200
| 350 | 480
| 600 | 760
| 768 |
HORZSIZE | 240
| 240 | 208
| 208 | 280
| 208 |
VERTSIZE | 180
| 175 | 156
| 152 | 210
| 152 |
ASPECTX | 5
| 38 | 36
| 36 | 10
| 36 |
ASPECTY | 12
| 48 | 36
| 36 | 14
| 36 |
ASPECTXY | 13
| 61 | 51
| 51 | 14
| 51 |
LOGPIXELSX | 96
| 96 | 96
| 96 | 120
| 96 |
LOGPIXELSY | 48
| 72 | 96
| 96 | 120
| 96 |
Из этой таблицы видны недостатки физической системы координат.
Во-первых, вертикальное (VERTRES) и горизонтальное (HORZRES) разрешение
зависит от типа видеоконтроллера.
Во-вторых, физические размеры пикселов (ASPECTX и ASPECTY ), и,
что самое главное, отношение высоты и ширины пиксела также зависят
от типа видеоконтроллера.
Если приложению требуется нарисовать, например, окружность или
квадрат, при использовании физической системы координат придется
учитывать форму пикселов, выполняя масштабирование изображения
по одной из осей координат. В противном случае вместо окружности
и квадрата на экране появятся эллипс и прямоугольник.
Логическая система координат
Приложения Windows могут использовать одну из нескольких логических
координат , устанавливая соответствующий режим отображения в контексте
отображения. При этом, как мы уже говорили, можно использовать
любое направление координатных осей и любое расположение начала
координат. Например, возможна система координат, в которой задаются
положительные и отрицательные координаты по любой оси (рис. 2.2).
Рис. 2.2. Одна из возможных систем координат
Для установки режима отображения, непосредственно определяющего
направление осей и размер логической единицы системы координат,
используется функция SetMapMode :
int WINAPI SetMapMode(HDC hdc, int nMapMode);
Для контекста отображения hdc эта функция устанавливает новый
режим отображения, заданный параметром nMapMode, возвращая номер
режима отображения, который был установлен раньше.
Параметр nMapMode может принимать одно из следующих значений.
Режим отображения | Направление оси X
| Направление оси Y | Размер одной логической единицы
|
MM_TEXT | Вправо | Вниз
| 1 пиксел |
MM_LOMETRIC | Вправо | Вверх
| 0,1 мм |
MM_HIMETRIC | Вправо | Вверх
| 0,01 мм |
MM_LOENGLISH | Вправо |
Вверх | 0,01 дюйм |
MM_HIENGLISH | Вправо |
Вверх | 0,001 дюйм |
MM_TWIPS | Вправо | Вверх
| 1/1440 дюйма |
MM_ISOTROPIC | Можно выбирать
| Можно выбирать | Произвольный, одинаковый для осей X и Y
|
MM_ANISOTROPIC | Можно выбирать
| Можно выбирать | Произвольный, может быть разный для осей X и Y
|
Как видно из этой таблицы, в режиме отображения MM_TEXT, выбранном
в контекст отображения по умолчанию, используется нестандартное
(для геометрии, математики и физики) направление оси Y - вниз
от начала координат. Мы уже говорили, что такое направление оси
Y удобно для отображения текста, поэтому этот режим отображения
иногда называют текстовым.
Нетрудно заметить, что в режиме MM_TEXT логическая единица длины
полностью соответствует физической, поэтому при рисовании геометрических
фигур возможны искажения формы. Эти искажения связаны с тем, что
форма пиксела для некоторых видеоконтроллеров может быть отличной
от квадратной. Режим MM_TEXT неудобен для рисования фигур.
В режимах MM_LOMETRIC, MM_HIMETRIC, MM_LOENGLISH, MM_HIENGLISH,
MM_TWIPS используется более привычное направление осей координат
и единицы длины, не зависящие от аппаратного обеспечения устройства
вывода.
В режиме MM_ISOTROPIC вы можете выбирать произвольное направление
осей координат и произвольный (но одинаковый) масштаб для осей
X и Y. Заметим, что произвольное направление координат в нашем
случае не подразумевает их произвольного расположения относительно
вертикальной и горизонтальной осей - ось X может располагаться
только горизонтально, ось Y - только вертикально.
Режим MM_ANISOTROPIC еще более универсален. Он позволяет устанавливать
произвольное направление осей координат, произвольный масштаб
для осей координат, причем для каждой оси можно установить свой
собственный масштаб.
Во всех режимах отображения, кроме MM_TEXT и MM_ANISOTROPIC с
разным масштабом для осей X и Y, приложение может не заботиться
о "квадратуре пиксела", так как масштаб по осям координат
одинаковый и не зависит от особенностей устройства вывода.
Сделаем небольшое пояснение относительно режима отображения MM_TWIPS.
В этом режиме используется единица длины twip (от twentieth of
a point - двадцатая часть точки, или, в терминах полиграфии, двадцатая
часть пункта). Размер одного пункта приблизительно равен 1/72
дюйма, следовательно размер единицы длины twip равен 1/1440 дюйма.
С помощью функции GetMapMode приложение может в любой момент времени
определить номер режима отображения, выбранный в контекст отображения
hdc:
int WINAPI GetMapMode(HDC hdc);
Преобразование координат
Теперь немного математики (не волнуйтесь, совсем немного).
Приложение, вызывая для рисования функции GDI, указывает логические
координаты. Перед выводом GDI преобразует их в физические с использованием
следующих формул:
В этих формулах используются следующие обозначения.
Переменные xWindow и yWindow обозначают, соответственно, логические
координаты по оси X и Y. Физические координаты обозначаются как
xViewport и yViewport. Таким образом, логические координаты (xWindow,yWindow)
преобразуются в физические координаты (xViewport,yViewport).
С помощью переменных xViewOrg и yViewOrg можно изменить расположение
начала физических координат. По умолчанию в контексте отображения
значения атрибутов, соответствующих этим переменным, равны 0.
Приложение может сместить начало координат, изменив значения переменных
xViewOrg и yViewOrg.
Для перемещения начала логической системы координат приложение
может изменить значения переменных xWinOrg и yWinOrg, которые
также определены как атрибуты контекста отображения. По умолчанию
в этих переменных находятся нулевые значения.
Переменные xViewExt, yViewExt, xWinExt и yWinExt (вернее, их отношения)
задают масштаб, который используется в процессе преобразования
координат. Этот масштаб зависит от установленного режима отображения.
Приложения могут изменить его только в режимах MM_ISOTROPIC и
MM_ANISOTROPIC , для остальных режимов отображения используются
фиксированные значения.
Обратные преобразования (из логических координат в физические)
выполняются с использованием следующих формул:
Для выполнения подобных вычислений удобна функция MulDiv , определенная
в программном интерфейсе Windows:
int WINAPI MulDiv(
int nMultiplicand, // множимое
int nMultiplier, // множитель
int nDivisor); // делитель
Эта функция выполняет умножение 16-разрядного параметра nMultiplicand
на 16-разрядный параметр nMultiplier, а затем делит полученное
32-разрядное произведение на 16-разрядный параметр nDivisor. В
случае переполнения или при нулевом значении делителя функция
возвращает отрицательное значение 32768.
Однако есть специальные функции, предназначенные для преобразования
логических координат в физические и физических в логические. Это
функции LPtoDP и DPtoLP.
Функция LPtoDP выполняет преобразование логических координат в
физические , причем одновременно можно преобразовать несколько
пар координат, что ускоряет работу приложения за счет сокращения
количества вызовов функции:
BOOL WINAPI LPtoDP(
HDC hdc, // идентификатор контекста отображения
POINT FAR* lppt, // указатель на массив структур POINT
int cPoints); // размер массива структур POINT
Параметр hdc указывает контекст отображения, для которого требуется
выполнить преобразования. В процессе преобразования используются
атрибуты контекста, такие как смещение и масштаб осей координат.
Через параметр lppt передается указатель на массив структур POINT,
в котором находятся преобразуемые координаты. Размер массива определяется
значением параметра cPoints. Структура POINT определена в файле
windows.h следующим образом:
typedef struct tagPOINT
{
int x;
int y;
} POINT;
После успешного выполнения преобразования функция возвращает значение
TRUE. При возникновении ошибки возвращается FALSE.
Обратное преобразование (физических координат в логические ) выполняется
функцией DPtoLP :
BOOL WINAPI DPtoLP(
HDC hdc, // идентификатор контекста отображения
POINT FAR* lppt, // указатель на массив структур POINT
int cPoints); // размер массива структур POINT
Назначение параметров функции DPtoLP и возвращаемое ей значение
аналогично назначению параметров и возвращаемому значению функции
LPtoDP.
Есть еще две функции, предназначенные для преобразования координат
- ClientToScreen и ScreenToClient.
Функция ClientToScreen выполняет преобразование координат в системе
координат, связанной с внутренней областью окна, в экранные координаты:
void WINAPI ClientToScreen(HWND hwnd, POINT FAR* lppt);
Параметр hwnd содержит идентификатор окна, для которого выполняется
преобразование.
Параметр lppt содержит указатель на структуру типа POINT, в которую
перед вызовом функции следует записать преобразуемые координаты.
Функция ScreenToClient имеет аналогичные параметры, но выполняет
обратное преобразование:
void WINAPI ScreenToClient(HWND hwnd, POINT FAR* lppt);
Режимы отображения
Теперь, после того как мы рассказали о физических и логических
координатах, а также о преобразованиях координат, займемся подробным
описанием каждого режима отображения .
Режим MM_TEXT
Режим отображения MM_TEXT устанавливается в контексте отображения
по умолчанию. Для этого режима формулы преобразования координат
упрощаются:
xViewport = (xWindow - xWinOrg) + xViewOrg
yViewport = (yWindow - yWinOrg) + yViewOrg
Соответствующая система координат представлена на рис. 2.3 (начало
системы координат расположено точно в левом верхнем углу внутренней
области окна, рисунок иллюстрирует только направление координатных
осей).
Рис. 2.3. Система координат в режиме отображения MM_TEXT
Так как в формуле преобразования не присутствуют переменные xViewExt,
yViewExt, xWinExt и yWinExt, в данном режиме преобразования невозможно
изменить масштаб осей координат. Поэтому логическая единица длины
в режиме отображения MM_TEXT равна физической, т. е. одному пикселу.
Тем не менее, приложение может изменить смещение физической или
логической системы координат, изменив, соответственно, значение
пар переменных (xViewOrg, yViewOrg) и (xWinOrg,yWinOrg). Для установки
смещения можно использовать функции SetViewportOrg и SetWindowOrg.
Функция SetViewportOrg устанавливает смещение физической системы
координат:
DWORD WINAPI SetViewportOrg(
HDC hdc, // контекст отображения
int nXOrigin, // новое значение для xViewOrg
int nYOrigin); // новое значение для yViewOrg
Для контекста отображения hdc эта функция устанавливает новое
расположение начала физической системы координат. Младшее и старшее
слово возвращаемого значения содержат, соответственно, предыдущие
x- и y-координаты начала физической системы координат.
С помощью функции SetWindowOrg вы можете установить начало логической
системы координат:
DWORD WINAPI SetWindowOrg(
HDC hdc, // контекст отображения
int nXOrigin, // новое значение для xWinOrg
int nYOrigin); // новое значение для yWinOrg
По своему смыслу параметры nXOrigin и nYOrigin являются логическими
x- и y-координатами верхнего угла окна, используемого для отображения
(так как в формуле они используются со знаком минус).
Как правило, приложения изменяют либо начало физических координат,
вызывая функцию SetViewportOrg, либо начало логических координат,
вызывая функцию SetWindowOrg, хотя, в принципе, вы можете изменить
и то, и другое (если не боитесь запутаться в координатных "сетях").
В программном интерфейсе Windows версии 3.1 есть новые варианты
описанных выше двух функций, которые называются SetViewportOrgEx
и SetWindowOrgEx . Они отличаются более удобным способом передачи
старых координат начала соответствующей системы координат:
BOOL WINAPI SetViewportOrgEx(
HDC hdc, // контекст отображения
int nXOrigin, // новое значение для xWinOrg
int nYOrigin, // новое значение для yWinOrg
POINT FAR* lppt); // указатель на структуру POINT
BOOL WINAPI SetWindowOrgEx(
HDC hdc, // контекст отображения
int nXOrigin, // новое значение для xWinOrg
int nYOrigin, // новое значение для yWinOrg
POINT FAR* lppt); // указатель на структуру POINT
В структуру, адрес которой передается через параметр lppt, записываются
старые координаты начала системы координат. Обе функции возвращают
TRUE в случае успеха и FALSE при возникновении ошибки.
В любой момент времени вы можете определить расположение начала
физических или логических координат, если воспользуетесь функциями
GetViewportOrg и GetWindowOrg (или их более новыми аналогами -
GetViewportOrgEx и GetWindowOrgEx).
Функция GetViewportOrg возвращает x- и y-координаты начала физической
системы координат для контекста отображения hdc:
DWORD WINAPI GetViewportOrg(HDC hdc);
Младшее и старшее слово возвращаемого значения содержат, соответственно,
предыдущие x- и y-координаты начала физической системы координат.
Функция GetWindowOrg возвращает x- и y-координаты начала логической
системы координат:
DWORD WINAPI GetWindowOrg(HDC hdc);
Новые функции, появившиеся в Windows версии 3.1, с именами GetViewportOrgEx
и GetWindowExtEx записывают координаты начала координат в структуру,
адрес которой передается через параметры lppt и lpSize:
BOOL WINAPI GetViewportOrgEx(HDC hdc, POINT FAR* lppt);
BOOL WINAPI GetWindowExtEx(HDC hdc, SIZE FAR* lpSize);
Структура SIZE определена для Windows версии 3.1 и описана в файле
windows.h следующим образом:
typedef struct tagSIZE
{
int cx;
int cy;
} SIZE;
Определены также разнообразные указатели на структуру SIZE:
typedef SIZE* PSIZE;
typedef SIZE NEAR* NPSIZE;
typedef SIZE FAR* LPSIZE;
Метрические режимы отображения
Режим MM_LOMETRIC , наряду с режимами MM_HIMETRIC , MM_LOENGLISH
, MM_HIENGLISH и MM_TWIPS, относится к метрическим режимам. Эти
режимы отображения позволяют использовать привычные единицы измерения,
такие как миллиметры и дюймы.
В метрических режимах отображения используются полные формулы
преобразования координат, приведенные выше в разделе "Преобразование
координат". В этих формулах приложение может изменять переменные,
определяющие смещение начала физической или логической системы
координат xViewOrg, yViewOrg, xWinOrg и yWinOrg.
Приложение не может изменить значения переменных xViewExt, yViewExt,
xWinExt и yWinExt, от которых зависит масштаб по осям координат.
Отношения xViewExt/xWinExt и yViewExt/yWinExt имеют фиксированное
значение для каждого из метрических режимов отображения.
Заметим, что для этих режимов отношение yViewExt/yWinExt имеет
отрицательный знак, в результате чего ось Y оказывается направленной
снизу вверх.
Обратим ваше внимание на одно важное обстоятельство, связанное
с использованием метрических режимов отображения.
Сразу после переключения в метрический режим отображения система
координат примет достаточно странный вид (рис. 2.4).
Рис. 2.4. Ориентация осей сразу после переключения в метрический
режим отображения
Ось X, как и следовало ожидать, окажется направленной слева направо,
а ось Y - снизу вверх. Точка с координатами (0,0) будет находиться
в верхнем левом углу экрана, поэтому для того чтобы нарисовать
что-нибудь в такой системе координат, вам придется для y-координаты
графических объектов использовать отрицательные числа. Для того
чтобы система координат приняла более удобный вид, можно переместить
начало физических координат в нижний левый угол окна или в центр
окна.
Прежде, чем выполнять перемещение начала координат, следует определить
размеры внутренней области окна. Это можно сделать при обработке
сообщения WM_SIZE :
static short cxClient, cyClient;
....
case WM_SIZE:
{
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
....
return 0;
}
Для того чтобы расположить начало координат в левом нижнем углу
окна, следует вызвать функцию SetViewportOrg, передав ей новые
координаты начала физической системы координат (0,cyClient):
SetViewportOrg(hdc, 0, cyClient);
Полученная в результате система координат показана на рис. 2.5.
Рис. 2.5. Метрическая система координат, начало координат
находится в левом нижнем углу окна
Аналогичным образом можно расположить начало системы координат
в середине окна (рис. 2.6), обеспечив возможность использования
положительных и отрицательных координат вдоль оси X и Y:
SetViewportOrg(hdc, cxClient/2, cyClient/2);
Рис. 2.6. Метрическая система координат, начало координат
находится в центре окна
Режимы MM_ISOTROPIC и MM_ANISOTROPIC
Режимы отображения MM_ISOTROPIC (изотропный) и MM_ANISOTROPIC
(анизотропный) допускают изменение направления осей X и Y, а также
изменение масштаба осей координат. В изотропном режиме отображения
MM_ISOTROPIC масштаб вдоль осей X и Y всегда одинаковый (т. е.
для обоих осей используются одинаковые логические единицы длины).
Анизотропный режим MM_ANISOTROPIC предполагает использование разных
масштабов для разных осей (хотя можно использовать и одинаковые
масштабы).
Для изменения ориентации и масштаба осей предназначены функции
SetViewportExt, SetViewportExtEx, SetWindowExt и SetWindowExtEx.
Функция SetWindowExt устанавливает для формулы преобразования
координат значения переменных xWinExt и yWinExt:
DWORD WINAPI SetWindowExt(
HDC hdc, // идентификатор контекста отображения
int nXExtent, // значение для xWinExt
int nYExtent); // значение для yWinExt
Функция SetViewportExt должна использоваться после функции SetWindowExt.
Она устанавливает для формулы преобразования координат значения
переменных xViewExt и yViewExt:
DWORD WINAPI SetViewportExt(
HDC hdc, // идентификатор контекста отображения
int nXExtent, // значение для xViewExt
int nYExtent); // значение для yViewExt
Обе функции возвращают в младшем и старшем слове предыдущие значения
соответствующих переменных для оси X и Y.
Приведенные выше формулы можно использовать для установки отношений
xViewExt/xWinExt и yViewExt/yWinExt, определяющих масштаб и направление
осей координат (направление осей координат зависит от знака этих
отношений).
Функции SetWindowExt передаются значения, соответствующие логическому
размеру логического окна, в которое будет выполняться вывод, а
функции SetViewportExt - реальные ширина и высота реального окна.
Например, нам надо создать систему координат, в которой начало
отсчета расположено в левом нижнем углу окна, ось X направлена
слева направо, а ось Y - снизу вверх. Высота и ширина должны изменяться
от 0 до 32767 (максимально возможное значение, так как для координат
используются 16-разрядные числа).
Если требуется получить одинаковый масштаб по осям X и Y, нужно
использовать изотропный режим отображения MM_ISOTROPIC.
Приведем фрагмент кода, создающий необходимый режим отображения.
SetMapMode(hdc, MM_ISOTROPIC);
SetWindowExt(hdc, 32767, 32767);
SetViewportExt(hdc, cxClient, -cyClient);
SetViewportOrg(hdc, 0, cyClient);
В изотропном режиме отображения при изменении размеров окна Windows
настроит систему координат таким образом, чтобы масштаб по осям
X и Y был одинаковый.
Если ширина окна больше высоты, масштаб по горизонтальной оси
настраивается таким образом, что логическое окно будет расположено
в левой части внутренней области окна (рис. 2.7).
Рис. 2.7. Изменение масштаба по горизонтали при увеличении
ширины окна в изотропном режиме
Если же высота окна больше его ширины, при использовании изотропного
режима отображения логическое окно окажется в нижней части внутренней
области окна (рис. 2.8).
Рис. 2.8. Изменение масштаба по горизонтали при увеличении
высоты окна в изотропном режиме
При использовании анизотропного режима отображения MM_ANISOTROPIC
настройка масштаба не выполняется, поэтому логическое окно будет
занимать всю внутреннюю поверхность окна при любом изменении размеров
этого окна (рис. 2.9 и 2.10).
Рис. 2.9. Изменение масштаба по горизонтали при увеличении
ширины окна в анизотропном режиме
Рис. 2.10. Изменение масштаба по горизонтали при увеличении
высоты окна в анизотропном режиме
В программном интерфейсе Windows версии 3.1 есть новые функции,
предназначенные для изменения масштабов осей. Это функции SetViewportExtEx
и SetWindowExtEx :
BOOL WINAPI SetViewportExtEx(
HDC hdc, // идентификатор контекста отображения
int nXExtent, // значение для xViewExt
int nYExtent, // значение для yViewExt
SIZE FAR* lpSize); // указатель на структуру SIZE
BOOL WINAPI SetWindowExtEx(
HDC hdc, // идентификатор контекста отображения
int nXExtent, // значение для xWinExt
int nYExtent, // значение для yWinExt
SIZE FAR* lpSize); // указатель на структуру SIZE
От функций SetViewportExt и SetWindowExt эти функции отличаются
тем, что старые значения переменных, определяющих масштаб преобразования,
записываются в структуру SIZE, указатель на которую передается
через параметр lpSize.
Изотропный режим отображения удобно использовать в тех случаях,
когда надо сохранить установленное отношение масштабов осей X
и Y при любом изменении размеров окна, в которое выводится изображение
(рис. 2.7 и 2.8).
Анизотропный режим удобен в тех случаях, когда изображение должно
занимать всю внутреннюю поверхность окна при любом изменении размеров
окна. Соотношение масштабов при этом не сохраняется (рис. 2.9
и 2.10).
В этом разделе мы расскажем вам об использовании функций, предназначенных
для рисования точек, линий, окружностей и других геометрических
фигур.
Несмотря на то, что в программном интерфейсе GDI имеется функция
SetPixel , позволяющая нарисовать один пиксел, не следует думать,
что рисование линии или окружности сводится к многократному вызову
этой функции. Если бы это было так, процесс рисования занимал
бы очень много времени. На самом деле многие из функций рисования
выполняются драйвером или даже аппаратурой видеоконтроллера, что
значительно ускоряет вывод.
С помощью функции GetDeviceCaps приложение может определить, поддерживает
ли драйвер ту или иную функцию рисования.
Первый параметр функции hdc задает контекст устройства, для которого
необходимо получить информацию о его возможностях.
Второй параметр iCapability определяет параметр устройства, значение
которого необходимо получить.
Приведем список значений для второго параметра функции GetDeviceCaps,
с помощью которых можно определить, какие операции рисования выполняет
драйвер устройства вывода.
Имя константы | Описание |
LINECAPS | Способности устройства рисовать линии. Возвращаемое значение представляет собой набор битовых масок, установленных в 1, если устройство может само рисовать линии различного типа:LC_INTERIORS устройство может закрашивать внутреннюю область;LC_MARKER маркеры;LC_NONE устройство не может рисовать линии;LC_POLYLINE ломаные линии;LC_POLYMARKER линии polymarker;LC_STYLED устройство может рисовать линии с использованием различных стилей (штриховые, пунктирные, штрих пунктирные и т.д.);LC_WIDE широкие линии;LC_WIDESTILED устройство может рисовать широкие линии с использованием различных стилей (штриховые, пунктирные, штрих-пунктирные и т. д.)
|
CURVECAPS | Способность устройства рисовать различные кривые линии и геометрические фигуры. Возвращаемое значение представляет собой набор битовых масок, установленных в 1, если устройство может само рисовать различные фигуры:CC_CIRCLES окружности;CC_CHORD сегмент эллипса;CC_ELLIPSES эллипсы;CC_INTERIORS устройство может закрашивать внутреннюю область геометрических фигур;CC_NONE устройство не может рисовать кривые линии и геометрические фигуры;CC_PIE секторы эллипса;CC_ROUNDRECT прямоугольники со скругленными углами;CC_STYLED устройство может рисовать рамки с использованием различных стилей (штриховые, пунктирные, штрих-пунктирные и т.д.);CC_WIDE широкие рамки;CC_WIDESTYLED устройство может рисовать широкие рамки с использованием различных стилей (штриховые, пунктирные, штрих-пунктирные и т. д.)
|
POLYGONALCAPS | Способности устройства рисовать многоугольники. Возвращаемое значение представляет собой набор битовых масок, установленных в 1, если устройство может само рисовать многоугольники различного типа:PC_INTERIORS устройство может закрашивать внутреннюю область;PC_NONE устройство не может рисовать многоугольники;PC_RECTANGLE прямоугольники;PC_SCANLINES устройство может выполнять сканирование линий растра;PC_STYLED устройство может рисовать рамки с использованием различных стилей (штриховые, пунктирные, штрих-пунктирные и т. д.);PC_WIDE широкие рамки;PC_WIDESTILED устройство может рисовать широкие рамки с использованием различных стилей (штриховые, пунктирные, штрих-пунктирные и т. д.)PC_WINDPOLYGON многоугольники с заполнением в режиме WINDING
|
Для приложения не имеет особого значения, кто именно будет рисовать
- видеоконтроллер, драйвер или GDI. Запрос на рисование, например,
эллипса, будет выполнен, даже если соответствующая операция не
поддерживается драйвером. В последнем случае эллипс будет нарисован
самим GDI с использованием более примитивных операций, но процесс
рисования займет больше времени.
Учитывая сказанное выше, не следует строить работу приложений
таким образом, чтобы периодичность вывода или скорость работы
приложения зависела от скорости рисования (подобная практика не
приветствуется и при создании программ для MS-DOS, вспомните,
как ведут себя старые игры, разработанные для процессора 8088,
на компьютерах с процессорами i80386 или i486). Современные видеоадаптеры
сконструированы таким образом, что большинство основных операций
рисования, используемых в операционной системе Windows, выполняются
аппаратно. Эти видеоадаптеры иногда называются ускорителями Windows.
Скорость рисования для ускорителя Windows может превышать в десятки
раз скорость рисования для обычного адаптера VGA или SVGA.
Результат рисования геометрических фигур зависит от установки
таких атрибутов контекста, как ширина, цвет и стиль линии (определяются
выбранным в контекст отображения пером), способ закраски замкнутых
фигур (определяется выбранной в контекст отображения кистью),
цвета фона, прозрачностью фона (прозрачный режим TRANSPARENT и
непрозрачный режим OPAQUE ), режимом рисования, режимом закрашивания,
областью ограничения, режимом отображения, т. е. практически от
всех атрибутов контекста отображения. Поэтому при описании функций
мы будем попутно описывать способы изменения атрибутов контекста
отображения, влияющих на результат их выполнения.
Работа с цветовыми палитрами и битовыми изображениями будут рассмотрены
позже в отдельных разделах, так как эти вопросы далеко не тривиальны
и поэтому заслуживают отдельного обсуждения.
Итак, перейдем непосредственно к описанию функций рисования геометрических
фигур.
Рисование точки
Функция рисования точки SetPixel устанавливает цвет точки с заданными
координатами:
COLORREF WINAPI SetPixel(
HDC hdc, // контекст отображения
int nXPos, // x-координата точки
int nYPos, // y-координата точки
COLORREF clrref); // цвет точки
Установка первых трех параметров этой функции не должна вызывать
у вас никаких затруднений. Параметр hdc определяет контекст отображения,
для которого необходимо изменить цвет точки. Параметры nXPos и
nYPos определяют координаты точки в системе координат, которая
зависит от установленного для контекста hdc режима отображения.
Последний параметр clrref определяет новый цвет точки. О том,
как "раскрасить" окно приложения, вы узнаете из третьей
главы нашей книги. Тем не менее мы опишем самый простой способ
для функции SetPixel.
В файле windows.h есть описание макрокоманды RGB , позволяющей
сконструировать цвет в формате COLORREF из отдельных компонент
красного (r), зеленого (g) и голубого (b) цвета:
#define RGB(r,g,b) \
((COLORREF)(((BYTE)(r)|((WORD)(g)<<8)) | \
(((DWORD)(BYTE)(b))<<16)))
Вы можете использовать эту макрокоманду совместно с функцией SetPixel
для установки, например, красного цвета точки, расположенной в
начале системы координат (0,0), следующим образом:
SetPixel(hdc, 0, 0, RGB(0xff, 0, 0));
Три параметра макрокоманды RGB позволяют задать любой из примерно
16 млн. цветов и оттенков, однако это не означает, что вы получите
на экране точно такой цвет, какой был задан при помощи этой макрокоманды.
Скорее всего вы сможете воспользоваться одним из 20 системных
цветов. Причины этого вы узнаете в третьей главе. Там же мы расскажем
о том, как в некоторых случаях можно расширить используемую гамму
цветов.
Функция SetPixel возвращает цвет, который фактически был использован
для рисования точки. Как мы только что заметили, возвращенное
значение может отличаться от заданного параметром clrref. В случае
ошибки оно будет равно -1.
Функция GetPixel позволяет узнать цвет точки, заданной идентификатором
контекст