Многим типам приложений Windows для организации полного интерфейса пользователя нужны только окна, блоки диалога и управляющие элементы. Но некоторым приложениям (например, программами рисования и манипулирования изображениями) требуется наличие графических средств для заполнения окон. Эта графика может быть в форме линий, форм, текста и побитовых образов.
    Для предоставления приложениям графических функциональных возможностей Windows имеет набор функций, называемый интерфейсом с графическим устройством - GDI. GDI можно представить себе как графическую машину, которую используют приложения Windows для отображения и манипулирования графикой. Функции GDI предоставляют вашему приложению возможности рисования, которые не зависят от используемого дисплея. Например, вы можете использовать одни и те же функции для организации вывода на дисплей EGA, на дисплей VGA и даже на принтер PostScript.
    Аппаратная независимость реализуется через использование драйверов устройств, которые переводят функции GDI в команды, воспринимаемые используемым устройством вывода. Это означает, что вам не нужно беспокоиться о том, как конкретное устройство работает с графическим образом. Вы сообщаете драйверу, что нужно что-то сделать, и он работает с устройством как нужно.
    В отличие от традиционных графических программ DOS программы
Windows никогда не выводят элементы изображения непосредственно
на экран или на принтер, а записывают их в логическую сущность,
называемую контекстом дисплея. Контекст дисплея - это виртуальная
поверхность с присущими ей атрибутами, такими как перо, кисть,
шрифт, цвет фона, цвет текста и текущая позиция. Для вашего
приложения, независимо от того, какое это на самом деле устройство,
все контексты устройства выглядят аналогично.
    Когда вы вызываете функции GDI для рисования в контексте
устройства, связанный с этим контекстом драйвер устройства
переводит действия по рисованию в соответствующие команды. Эти
команды воспроизводят насколько возможно точно действия рисования на
дисплее, независимо от возможностей самого дисплея. Дисплей может
быть монохромным экраном низкого разрешения или экраном с
четырьмя миллионами цветовых оттенков.
    Контекст дисплея можно представить себе как холст для
рисования. Окно это - картинка, включающая рамку. Вместо рисования на
картине в рамке вы рисуете на холсте, а уже затем устанавливаете
его в рамку. Аналогично этому, вы рисуете в контексте дисплея
окна. Контекст дисплея обладает рядом инструментов рисования,
например, ручки, кисти и шрифты. Контекст дисплея - это управляемый
Windows элемент, похожий на элемент окна с тем исключением, что
контекст дисплея не имеет соответствующего элемента
ObjectWindows.
    Нужно помнить о том, что контекст устройства представляет
собой только часть устройства, на котором вы реально рисуете.
Хотя вы можете рассматривать вывод в терминах всего окна (рамки,
меню, области клиента) или печатаемой страницы, контекст
устройства охватывает только ту часть, где вы рисуете - область клиента
окна или печатаемую часть страницы.
    Контекст устройства - это элемент, управляемый Windows
(аналогично оконному элементу, только контекст устройства не имеет
соответствующего объекта ObjectWindows).
    Для областей клиента окна Windows обеспечивают специальные
контексты устройства, называемые контекстами дисплея. Вместо
представления самого устройства, такого как экран или принтер,
контекст дисплея позволяет вам интерпретировать область клиента
окна как целое устройство.
    На практике контекст дисплея вам не требуется
интерпретировать как-то иначе, чем другой контекст устройства. Он позволяет
вам работать так, как если бы ваше окно было целым устройством,
так что вам не нужно беспокоиться о смещении позиции на экране и
т.д.
    Для организации рисования в контексте дисплея сначала нужно
получить контекст дисплея для нужного окна. Требования к памяти
со стороны контекста дисплея очень велики, поэтому можно
одновременно организовать доступ только к пяти контекстам дисплея в
каждом сеансе Windows. Это значит, что каждое окно не может
поддерживать свой собственный контекст дисплея. Оно получает его только
в случае необходимости и освобождает при первой возможности. Это
может несколько обескуражить вас, но вы не можете управлять
атрибутами контекста дисплея. Другое окно и даже другое приложение
может сменить атрибуты контекста дисплея. Кроме того, средства
рисования не являются частью памяти контекста дисплея. Они могут
быть выбраны в контекст дисплея каждый раз при его получении.
    Обычно нужно определять поле оконного объекта для записи
описателя текущего контекста дисплея, аналогично тому, как в
HWindow сохраняется описатель окна:
    Чтобы получить для окна контекст дисплея, вызовите функцию
Windows GetDC:
    Затем вы можете выполнить операцию изображения в контексте
дисплея. Вы можете использовать описатель контекста дисплея в
графических функциях Windows:
    Как только вы закончите работу с контекстом дисплея,
освободите его с помощью вызова функции ReleaseDC:
    Не вызывайте GetDC в строке дважды, не включив между
вызовами вызов ReleaseDC. В итоге это приведет к сбою системы при
работе программы, так как она исчерпает все доступные контексты
дисплея.
    Контекст устройства содержит набор изобразительных средств,
таких как перья, кисти и шрифты. Реально эти инструментальные
средства не существуют. Они просто представляют собой удобный
способ предположений об определенной группе изобразительных
характеристик.
    Перо, например, это просто удобный способ интерпретации
характеристик линий на устройстве. Графическая линия между двумя
точками имеет три характеристики: ширину, цвет и стиль (например,
пунктирная линия и линия из точек), которые совместно можно
рассматривать как "перо". Эти логические группы изобразительных
характеристик значительно упрощают графику в Windows.
    Хотя обычно вам не нужно будет изменять большинство
атрибутов контекста дисплея, важно по крайней мере знать, что в нем
содержится. Данный раздел кратко описывает некоторые элементы
контекста дисплея, включая побитовые отображения, цвета, области и
изобразительные средства. Некоторые из этих тем также
рассматриваются более подробно в некоторых других разделах данной главы.
    Действительная поверхность контекста дисплея называется
побитовым отображением (битовым массивом). Побитовые отображения
представляют конфигурацию памяти конкретного устройства.
Следовательно, они зависят от вида адресуемого устройства. Это создает
проблему, поскольку охраненные для одного устройства побитовые
отображения будут несовместимы с другим устройством. GDI имеет
ряд средств для разрешения этой проблемы, включая
аппаратно-независимые побитовые отображения. Имеются следующие функции GDI,
которые создают побитовые отображения: CreateCompatibleDC,
CreateCompatibleBitmap и CreateDIBitmap. Имеются следующие
функции GDI по манипулированию побитовыми отображениями: BitBlt,
StretchBlt, StretchDIBits и SetDIBitsToDevice.
    Чтобы выполнить большую часть фактического изображения,
контекст дисплея использует три инструментальных средства: перо,
кисть и шрифт.
    Перо используется для изображения линий, дуг и ломаных
линий, представляющих собой множественные линейные сегменты.
Атрибуты пера включают в себя его цвет, ширину и стиль (например,
пунктирная линия или линия из точек).
    Кисть используется при закраске замкнутых фигур, таких как
прямоугольники, прямоугольники с округлыми краями и
многоугольники. Функции, рисующие непрерывные формы используют перо для
вычерчивания границ, а кисть - для закраски внутренней области.
Существуют четыре типа кистей - непрерывные, с засечками, с
образцом побитового отображения и с независимым от устройств образцом
побитового отображения.
    Инструментальное средство шрифта используется при
изображения в контексте дисплея текста. Оно задаете высоту шрифта, его
ширину, семейство и имя гарнитуры.
    Все три инструментальных средства используют для заполнения
пробелов атрибут фонового цвета контекста дисплея.
Изобразительные инструментальные средства подробнее освещаются в разделе
"Изобразительные средства" данной главы.
    Цвет, который устройство использует для рисования, хранится
в цветовой палитре. Если вы желаете добавить цвет, которого нет в
цветовой палитре, то его можно добавить. Более часто вы будете
настраивать драйвер устройства на аппроксимацию нужного цвета
путем смешивания цветов палитры. Работа с цветовой палитрой более
подробно рассматривается в разделе данной главы "Использование
цветовой палитры".
    Очень трудно выбрать устройство рисования, когда заранее
неизвестно, какое устройство будет использоваться для отображения.
Большинство приложений игнорируют эту проблему и предполагают,
что вполне удовлетворительно будет работать единица рисования по
умолчанию (один элемент изображения). Однако, некоторые
приложения требуют, чтобы отображение точно воспроизводило размеры
нужного образа. Для таких приложений GDI допускает различные режимы
отображения, некоторые из которых не зависят от аппаратуры.
Каждый из методов распределения имеет свою единицу размерности и
систему координатной ориентации. Режим распределения по умолчанию
устанавливает начало координат в левом верхнем углу контекста
дисплея с положительным направлением оси X вправо и положительным
направлением оси Y вниз. Каждый контекст дисплея имеет атрибуты
распределения для интерпретации задаваемых вами координат.
    Иногда нужно транслировать логические координаты,
используемые вами для рисования, в физические координаты побитового
отображения. Для большинства приложений начало координат для экрана
это его левый верхний угол, но для окна началом координат будет
левый верхний угол области клиента. Некоторые окна прокручивают
свою поверхность клиента так, что начало координат не будет даже
находиться в области клиента. Некоторые функции GDI работают
только в конкретной системе координат, поэтому преобразование
координат просто необходимо. В GDI имеется ряд функций для
подобного пересчета координат: ScreenToClient, ClientToScreen, DPToLP и
LPToDP.
    Для предотвращения рисования вне заданной области каждый
контекст дисплея имеет атрибут области вырезанного изображения.
Область вырезанного изображения может быть сложным
многоугольником или эллипсом, внутри которого и может происходить
действительное рисование на виртуальной поверхности контекста дисплея.
Для большинства приложений выделяемая по умолчанию область
вырезанного изображения будет вполне достаточной. Изменять эту
область придется только для приложений, которые воспроизводят
некоторые специальные визуальные эффекты.
    Контекст дисплея управляет отображением графики на экране.
Для иного способа отображения графики можно изменить
инструментальные средства, с помощью которых создается изображение.
Атрибуты инструментальных средств задают проявление изображений с
помощью функций GDI, например, LineTo, Rectange и TextOut. Перья
задают внешний вид линий, кисти задают внешний вид закрашенных
областей и шрифт задает внешний вид изображаемого текста.
    Для задания атрибутов инструмента программа Windows выбирает
логический инструмент в контекст дисплея. Логический инструмент
создается вашей программой путем заполнения полей определенной
записи, TLogPen, TLogBrush или TLogFont. Текущий инструмент - это
инструмент, определенный в Windows, представляющий самый общие
варианты атрибута, например, непрерывное черное перо, серая кисть
или системный шрифт.
    Основные инструментальные средства создаются функцией GDI
GetStockObject. Например:
где LtGray_Brush - это целая константа, определенная в модуле
WinTypes в ObjectWindows. Приведем список всех имеющихся констант
основного инструментального средства:
    В отличие от логических инструментальных средств основные
инструментальные средства не удаляются после использования.
    Записи логических инструментов, TLogPen, TLogBrush и
TLogFont, содержат поля для хранения каждого атрибута
инструмента. Например, TLogPen.lopnColor содержит значение цвета ручки.
Каждый тип записи определяет свой собственный набор атрибутов,
соответствующий типу инструмента.
    Вы можете создавать логические перья с помощью функций
Windows CreatePen или CreatePenInderect. Например:
    Определение записи TLogPen имеет следующий вид:
    Поле стиля, lopnStyle, содержит константу, задающую стиль
линии.
    Поле толщины, lopnWidth, содержит точку, координата x
которой задает толщину линии в координатах устройства. На экране VGA,
если задано значение 0, то будет рисоваться линия толщиной в один
элемент изображения. Значение координаты y игнорируется. Поле
цвета, lopnColor, содержит значение Longint, байты которого
задают величины интенсивности основных цветов (красного, зеленого и
синего), смешение которых и дает нужный цвет. Значение lopnColor
должно иметь вид $00bbggrr, где bb - значение синего цвета, gg
значение зеленого цвета, а rr - значение красного цвета.
Доступный диапазон интенсивности для каждого первичного цвета от 0 до
255, или от 0 до FF в шестнадцатиричном исчислении. Следующая
таблица показывает некоторые примеры значений цвета:
    В качестве альтернативы для воспроизведения цвета можно
использовать функцию RGB. RGB(0,0,0) возвратит черный цвет,
RGB(255,0,0) возвратит красный и т.д.
    Вы можете создавать логические кисти с помощью функций
Windows CreateHatchBrush, CreatePatternBrush,
CreateDIBPatternBrush или CreateBrushInderect. Например:
    Определение записи TLogBrush имеет следующий вид:
    Поле стиля, lbStyle, содержит константы, задающие стиль
кисти:
    Поле lbColor содержит значение цвета, аналогично записи
TLogPen. Это поле игнорируется кистями со стилями bs_Hollow и
bs_Pattern.
    Поле lbHatch содержит целую константу, задающую образец
штриховки для кисти со стилем bs_Hatched. Если стиль
bs_DIBPattern, то lbHatch содержит описатель побитового
отображения.
    Вы можете создавать логические шрифты с помощью функций
Windows CreateFont или CreateFontInderect.
    Определение записи TLogBrush следующее:
    При использовании TLogFont для создания шрифта вы задаете
атрибуты нужного вам шрифта. Однако, ваша программа не использует
эту информацию для генерации шрифта на экране. Вместо этого она
отображает запрос экранного шрифта в текущий экранный шрифт
сеанса Windows.
    Поле lfHight задает необходимую высоту шрифта. Нулевое
значение устанавливает размер по умолчанию. Положительное значение
есть высота элемента в логических единицах. Отрицательное
значение воспринимается как положительное.
    Поле lfWidht задает нужную ширину букв в единицах
устройства. Если задан ноль, то коэффициент относительного удлинения
сохраняется.
    Для поворачиваемого текста lfEscapement задает значение в
десятых долях градуса, на которое поворачивается текст против
часовой стрелки. lfOrientation делает аналогичный поворот каждого
символа.
    Параметр lfWeight задает нужный вес символов. В качестве
значений можно использовать константы fw_Light, fw_Normal,
fw_Bold и fw_DontCare.
    Для трех атрибутов шрифта - lfItalic, lfUnderline и
lfStrikeOut - нужно задать ненулевые значения.
    В поле lfCharSet требуется задать конкретный набор символов,
ANSI_CharSet, OEM_CharSet или Symbol_CharSet. Набор символов ANSI
содержится в "Руководстве пользователя по Microsoft Windows", в
Приложении B. OEM_CharSet является системно-зависимым.
    Поле lfOutPrecision задает, как точно создаваемый Windows
шрифт должен соответствовать запросам на размеры и
позиционирование. Значение поля по умолчанию - Out_Default_Precis. Поле
lfClipPrecision задает способ рассмотрения частично видимых
символов. Значение поля по умолчанию Clip_Default_Precis.
    Поле lfQuality показывает как точно предоставляемый Windows
шрифт соответствует запрошенным атрибутам шрифта. Может быть
установлено значение Default_Quality, Draft_Quality или
Proof_Quality. Для значения Proof_Quality жирные, подчеркнутые,
наклонные шрифты и шрифты с надпечаткой синтезируются, даже если
их нет. Поле lfPitchAndFamily задает шаг и семейство шрифта. Оно
может быть результатом логической операции or между константой
шага и константой семейства.
    И, наконец, lfFaceName - это строка, которая задает
запрошенный вид букв. Если задано значение 0, то вид букв будет
строиться на основании значений других полей TLogFont. Приведем
несколько примеров исходного кода, определяющего записи TLogFont:
    Контекст дисплея позволяет вам рисовать в окне и, кроме
этого, он содержит инструментальные средства рисования: перья,
кисти, шрифты и палитры, которые вы используете для рисования текста
и изображений. При рисовании линии в контексте дисплея линия
выводится со следующими атрибутами текущего пера: цвет, стиль
(непрерывная, пунктирная и т.п.) и толщина. При закрашивании области
она выводится со следующими атрибутами текущей кисти: образец и
цвет. При рисовании текста в контексте дисплея он выведется с
атрибутами текущего шрифта: шрифт (Modern, Roman, Swiss и т.п.),
размер, стиль (наклонный, жирный и т.п.). Палитра содержит набор
текущих доступных цветов.
    Контекст дисплея содержит по одному типу каждого
инструментального средства рисования. Вновь полученный контекст дисплея
содержит набор инструментальных средств, используемых по
умолчанию: тонкое черное перо, непрерывная черная кисть, системный
шрифт и палитра по умолчанию. Если этот набор вас устраивает, то
нет необходимости его изменять.
    Для изменения набора инструментальных средств по умолчанию,
нужно создать новый инструментальный элемент и выбрать его в
контекст дисплея. Например, при выборе новой ручки старая
автоматически удаляется. Мы рекомендуем вам сохранять старые
инструментальные средства и повторно устанавливать их после окончания
использования новых:
    Как показано в данном примере, новый инструмент рисования
должен быть создан, а затем удален. Подобно контексту дисплея,
элементы хранятся в памяти Windows. Если их не удалить, это
приводит к потерям памяти и возможности возникновения сбоя. Как и
для контекста дисплея, вы должны хранить описатели
инструментальных средств рисования в переменных типа HPen, HBrush, HFont и
HPalette.
    Функция Windows DeleteObject удаляет инструментальные
средства рисования из памяти Windows. Ни в коем случае не удаляйте
инструментальные средства рисования, которые выбраны в данный
момент в контекст дисплея!
    Контекст дисплея может хранить только по одному инструменту
рисования каждого типа в данный момент времени, поэтому нужно
отслеживать доступные инструментальные средства отображения.
Очень важно удалить их все до завершения работы вашего
приложения. Один из методов, (использован в примере Главы 2) состоит в
определении поля объекта окна с именем ThePen для хранения
описателя текущего пера. Когда пользователь выбирает новый стиль пера,
создается новое перо, а старое удаляется. Следовательно,
окончательное перо будет удалено методом основного окна CanClose. Вам
не нужно удалять набор инструментальных средств по умолчанию,
поставляемый во вновь полученном контексте дисплея.
    Есть два способа создания новых инструментальных средств
рисования. Самый простой способ состоит в использовании
существующего альтернативного инструмента, называемого основным или
опорным. Список основных инструментальных средств приведен в Таблице
17.1.
    Для установки основного инструментального средства в объекте
контекста дисплея используются методы SetStockPen, SetStockBrush,
SetStockFont и SetStockPalette. Например:
    Не удаляйте основные инструменты из памяти Windows,
поскольку вы будете настраивать их. Иногда возникает ситуация, когда нет
основного инструмента, который имел бы нужный вам атрибут.
Например, все основные перья воспроизводят тонкие линии, а вам
требуется толстая. В этом случае имеется два способа создания
настроенных инструментальных средств рисования. Один способ состоит в
вызове функций Windows CreatePen, CreateFont, CreateSolidBrush
или CreateDIBPatternBrush. Эти функции используют параметры,
которые описывают нужный инструмент, и возвращают описатель
инструментального средства, который используется в вызовах
SelectObject.
    Другой способ создания настроенных инструментальных средств
состоит в построении описания атрибутов логического инструмента.
Логический инструмент реализуется структурами данных Windows
TLogPen, TLogBrush, TLogFont и TLogPalette. Например, TLogPen
имеет поля для хранения толщины цвета и стиля. После создания
записи данных логического инструмента, она передается в качестве
параметра в CreatePenInderect, CreateBrushInderect,
CreateFontInderect или CreatePalette. Эти функции возвращают
описатели инструментального средства которые могут быть использованы
в вызовах SelectObject. В данном примере устанавливается синее
перо для изображения в контексте дисплея окна:
    Рисование - это процесс отображения контекста окна.
Приложение Windows отвечает за рисование его окон при их первом
появлении и их изменении, например, после восстановления из пиктограммы
или перекрытия другими окнами. Windows не обеспечивает
автоматического рисования контекста окон, она только информирует окно,
когда ему нужно нарисовать себя. Данный раздел показывает, как
рисовать в окне, объясняет механизм рисования и объясняет
использование контекста дисплея.
    В данном разделе термин "рисование" относится к отображению
графики в окне. Рисование - это автоматическое отображение
графики при первом появлении или изменении окна. С другой стороны
рисование - это процесс создания и отображения специфических
изображений в другие моменты времени под управлением программы. Под
графикой понимается как текст, так и элементы изображения,
например, побитовые отображения и прямоугольники.
    Когда возникает необходимость нарисовать окно, оно
становится запрещенным. Это значит что изображение дисплея не
соответствует действительности и должно быть изменено. Это происходит в
момент первоначального отображения окна, восстановления из
пиктограммы или удаления другого окна, которое перекрывало часть
данного окна. Во всех этих случаях Windows посылает сообщение
wm_Paint соответствующему приложению. Это сообщение автоматически
вызывает метод Paint вашего окна. Один из параметров Paint,
PaintDC, представляет собой контекст дисплея, который
используется для рисования.
    Метод TWindow Paint ничего не рисует, поскольку объекты
TWindow не имеют графики для рисования. В типе вашего окна
определим метод Paint, который будет вызывать методы и функции,
изображающие в окне текст и графику.
    Единственное, что вы можете сделать с контекстом дисплея,
это выбрать в него новый инструмент рисования, например, перья
других цветов или кисти других образцов. Вам придется указать эти
инструменты в контексте дисплея рисования вашего метода Paint.
    После завершения работы метода Paint контекст дисплея
рисования автоматически освобождается.
    Метод Paint отвечает за рисование текущего содержимого окна
в любой момент времени, включая первое появление этого окна.
Следовательно, метод Paint должен уметь рисовать все "постоянные"
изображения окна. Кроме того, он должен уметь восстанавливать
любые изображения, добавленные в окно после его первого появления.
Для воспроизведения этой "динамической" графики метод Paint
должен иметь доступ к инструкциям или данным, с помощью которых было
создано изображение.
    Вы можете выбрать один из двух возможных вариантов. Первый
подход состоит в выделении нескольких графических методов и при
динамическом рисовании вызывать их из метода Paint. Другой
подход, показанный в примере Главы 3, состоит в хранении данных,
относящихся к графическому контексту окна, в полях объекта этого
окна. Эти данные могут включать, например, координаты, формулы и
побитовые распределения. Затем метод Paint повторно вызывает
графические функции, которые нужны для преобразования этих данных в
изображения.
    Используя эти стратегии и способность объекта хранить свои
собственные данные и функции вы можете разрабатывать очень
развитые и впечатляющие графические приложения.
    Для рисования любого текста или изображения в объекте окна
сначала нужно получить контекст дисплея. После рисования контекст
дисплея нужно освободить. (В одном сеансе Windows доступны только
пять элементов контекста дисплея.) Вы можете использовать
описатель контекста дисплея в качестве аргумента любой графической
функции Windows.
    Одно из правил GDI состоит в том, что для работы функций
необходимо в качестве аргумента задавать контекст дисплея. Обычно
вы будете вызывать эти функции из методов типа окна. Например,
TextOut - это функция рисования текста на контексте дисплея в
заданном месте:
    Данный раздел описывает различные вызовы API, которые вы
можете использовать для рисования изображений в окне.
    Функция рисования текста использует для рисования заданный
текущий шрифт контекста дисплея. Функция TextOut рисует текст в
заданной точке. TextOut выравнивает текст в зависимости от
текущих значений флагов форматирования текста. По умолчанию
происходит выравнивание слева. Текущий метод выравнивания можно
посмотреть с помощью функции GetTextAlign и установить с помощью
функции SetTextAlign.
    Функция TextOut - это самая часто используемая функция
рисования текста. Используя установленные по умолчанию флаги
форматирования текста, данный метод Paint рисует выравненный слева
массив символов, левый верхний угол которого имеет координаты
(10,15).
    Функции рисования линии используют для рисования заданное
текущее перо контекста дисплея. Большинство линий рисуется с
использованием функций MoveTo и LineTo. Эти функции воздействуют на
атрибут контекста дисплея - текущую позицию. Если использовать
аналогию с карандашом и листом бумаги, то текущая позиция это
точка, где карандаш касается бумаги.
    Функция MoveTo перемещает текущую позицию в заданные
координаты. Функция LineTo рисует линию из текущей позиции к точке с
заданными координатами. Заданные координаты затем становятся
текущей позицией. Следующий метод Paint рисует линию от (100,150)
до (10,15).
    Функция Polyline рисует последовательность линий,
соединяющих заданные точки. По действию она аналогична выполнению
последовательности функций MoveTo и LineTo, однако, Polyline выполняет
эту операцию намного быстрее и никак не воздействует на текущую
позицию пера. Следующий метод Paint рисует прямой угол.
    Функция Arc рисует дуги по периметру эллипса, ограниченного
заданным прямоугольником. Дуга начинается в точке пересечения
эллипса и линии из центра эллипса в заданную точку начала. Дуга
рисуется против часовой стрелки до тех пор, пока она не достигнет
точки пересечения эллипса с линией из центра эллипса к заданной
точке конца.
    Следующий метод Paint рисует верхнюю четверть окружности с
началом в (40,25) и окончанием в (10,25), используя
ограничивающий прямоугольник (10,10), (40,40), начальную точку (0,0) и
конечную точку (50,0). Действие производится даже в том случае,
если заданная начальная и конечная точка не лежат на дуге.
    Функции изображения фигур используют текущее перо заданного
контекста дисплея для изображения периметра и текущую кисть для
закраски внутренней области. На текущую позицию они не влияют.
    Функция Rectangle рисует прямоугольник от его левого
верхнего угла к правому нижнему. Например, следующий оператор метода
Paint рисует прямоугольник от (10,15) до (100,150).
    Функция RoundRect рисует прямоугольник со скругленными
углами. Скругления углов определены как четверти эллипса. Например,
следующий оператор метода Paint рисует прямоугольник от (10,15)
до (100,150), углы которого будут скруглены четвертями эллипса
шириной 9 и высотой 11.
    Функция Ellipse рисует эллипс, задаваемый ограничивающим его
прямоугольником. Следующий пример рисует эллипс в прямоугольнике
от (10,15) до (110,70).
    Функции Pie и Chord рисуют секторы эллипса. Они рисуют дугу,
подобно функции Arc. Однако, результатом Pie и Chord будут
области. Функция Pie соединяет центр эллипса с его граничными точками.
Следующая функция Pie рисует верхнюю четверть круга, заключенного
в прямоугольник от (10,10) до (40,40).
    Функция Chord соединяет две граничные точки дуги.
    Функция Polygon рисует непрерывную последовательность
сегментов линий, аналогично функции Polyline, но в конце работы
замыкает область, рисуя линию от последней заданной точки к первой
заданной точке. И, наконец, он заполняет полученный многоугольник
текущей кистью, используя установленный режим закрашивания
многоугольника. Следующий метод Paint рисует и закрашивает
прямоугольный треугольник.
    Некоторые типы дисплейных устройств компьютера могут
выводить множество цветов, но только ограниченное их число в каждый
момент времени. Системная или физическая палитра - это группа или
набор цветов, которые в данный момент доступны дисплею для
одновременного отображения. Windows дает вашему приложению частичное
управление цветами, входящими в системную палитру устройства.
Если ваше приложение использует только простые цвета, то вам нет
необходимости непосредственно использовать палитру.
    Однако, изменение палитры системы воздействует на все
изображение, имеющееся на экране, включая другие приложения. Одно
приложение может вызвать вывод всех других приложений в
некорректных цветах. Администратор палитры Windows разрешает эту
проблему, согласовывая изменения системной палитры с приложениями.
Windows предоставляет каждому приложению свою логическую палитру,
которая представляет собой группу цветов, используемых
приложением. Администратор палитры связывает запрошенные логической
палитрой цвета с имеющимися цветами системной палитры. Если
запрошенный цвет отсутствует в системной палитре, администратор палитры
может добавить его. Если в логической палитре задано больше
цветов, чем может содержаться в системной палитре, то для
дополнительных цветов подбирается максимально похожий цвет системной
палитры.
    Когда приложение становится активным, имеется возможность
заполнить системную палитру цветами из логической палитры. Это
действие может повлиять на распределение цветов, заданных
логическими палитрами других приложений. В любом случае Windows
резервирует 20 цветов в системной палитре для общего представления
цветовой гаммы всех приложений и самого Windows.
    Логические палитры являются инструментами рисования, такими
же как перья и кисти, описанные в разделе "Инструментальные
средства изображения". Для создания логической палитры
используется функция CreatePalette, которая берет указатель на запись
данных LogPalette, создает новую палитру и возвращает ее
описатель, который передается в SelectPalette для выбора палитры в
контекст дисплея. Запись TLogPalette содержит поля номера версии
Windows (в настоящее время $0300), число элементов палитры и
массив элементов палитры. Каждый элемент палитры - это запись типа
TPaletteEntry. Тип TPaletteEntry имеет три байтовых поля для
спецификации цвета (peRed, peGreen и peBlue) и одно поле для флагов
(peFlags).
    GetStockObject(Default_Palette) создает палитру по
умолчанию, состоящую из 20 цветов, которые всегда присутствуют в
палитре системы.
    После выбора палитры в контекст дисплея с помощью
SelectPalette, он должен до использования "реализовать" ее. Это
делается с помощью функции Windows RealizePalette:
    RealizePalette помещает цвета из вашей логической палитры в
системную палитру устройства. Сначала Windows проверяет
соответствие цветов с уже имеющимися в системной палитре, а затем
добавляет ваши новые цвета в палитру системы, если для этого есть
место. Цветам, которым не нашлись идентичные цвета в системной
палитре, подбирается наиболее соответствующий цвет из палитры
системы. Ваше приложение должно реализовать свою палитру до
рисования, как это делается для других инструментальных средств
рисования.
    После реализации палитры вашего приложения, оно может
осуществлять рисование с использованием его цветов. Цвета палитры
можно задавать прямо или косвенно. Для прямого задания цвета
используется индекс палитры, TColorRef. Индекс палитры TColorRef
есть значение типа Longint, где старший байт установлен в 1, а
индекс элемента логической палитры содержится в двух младших
байтах. Например, $01000009 задает девятый элемент логической
палитры. Это значение можно использовать везде, где ожидается аргумент
TColorRef. Например:
    Если ваше дисплейное устройство допускает использование
полного 24-битового цвета без системной палитры, то использование
индекса палитры неоправданно ограничивает вас цветами вашей
логической палитры. Чтобы избежать этого ограничения, вы можете
задать цвет палитры косвенно, используя относительное значение
палитры TColorRef. Относительное значение TColorRef почти совпадает
с абсолютным значением RGB TColorRef, но байт старшего разряда
установлен в 2. Три младших байта содержат значение цвета RGB.
Например, $020000FF задают значение чистого красного цвета. Если
устройство поддерживает системную палитру, то Windows подберет
максимально соответствующий цвет RGB логической палитры. Если
устройство не поддерживает системную палитру, то TColorRed
используется так, как если бы он задавал явное значение RGB.
    Windows определяет функцию, которая позволяет вам получать
информацию относительно палитры. GetPaletteEntries воспринимает
индекс, диапазон и указатель на TPaletteEntry и заполняет буфер
заданными элементами палитры.
Запись на устройство вывода
Чем отличаются контексты устройства?
Управление контекстом дисплея
Работа с контекстом дисплея
type
TMyWindows = object(TWindow)
TheDC: HDC;
.
.
.
end;
TheDC := GetDC(HWindow);
LineTo(TheDC, Msg.LParamLo, Msg.LParamHi);
ReleaseDC(HWindow, TheDC);
Что содержится в контексте устройства?
Побитовая графика
Изобразительные средства
Цвет
Режимы отображения
Обрезание областей
Инструментальные средства рисования
Основные инструментальные средства
var
TheBrush: HBrush
begin
TheBrush:=GetStockObject(LtGray_Brush);
.
.
.
end;
Кисти Перья Шрифты White_Brush White_Pen OEM_Fixed_Font LtGray_Brush Black_Pen ANSI_Fixed_Font Gray_Brush Null_Pen ANSI_Var_Font DkGray_Brush System_Font Black_Brush Device_Default_Font Null_Brush System_Fixed_Font Hoolow_Brush Логические инструментальные средства
Логические перья
ThePen := CreatePen(ps_Dot, 3, RGB(0, 0, 210));
ThePen := CreatePenInderect(@ALogPen);
TLogPen = record
lopnStyle: Word;
lopnWidth: TPoint;
lopnColor: Longint;
end;
Рис.17.1 Стили линий для пера.
Значение Цвет $00000000 черный $00FFFFFF белый $000000FF красный $0000FF00 зеленый $00FF0000 синий $00808080 серый Логические кисти
TheBrush := CreateHatchBrush(hs_Vertical, RGB(0, 255, 0));
TheBrush := CreateBrushInderect(@ALogBrush);
TLogBrush = record
lbStyle: Word;
lbColor: Longint;
lbHatch: Integer;
end;
Рис. 17.2 Стили штриховки для кисти.Логические шрифты
TLogFont = record
lfHight: Integer;
lfWidht: Integer;
lfEscapement: Integer;
lfOrientation: Integer;
lfWeight: Integer;
lfItalic: Byte;
lfUnderline: Byte;
lfStrikeOut: Byte;
lfCharSet: Byte;
lfOutPrecision: Byte;
lfClipPrecision: Byte;
lfQuality: Byte;
lfPitchAndFamily: Byte;
lfFaceName: array[0..lf_FaceSize - 1] of Byte;
end;
Константы шага Константы семейства Default_Pitch ff_Modern Fixed_Pitch ff_Roman Variable_Pitch ff_Script ff_Swiss ff_Decorative ff_DontCare
procedure MyWindow.MakeFont;
var
MyLogFont: TLogFont;
begin
with MyLogFont do
begin
lfHight := 30;
lfWidht := 0;
lfEscapement := 0;
lfOrientation := 0;
lfWeight := fw_Bold;
lfItalic := 0;
lfUnderline := 0;
lfStrikeOut := 0;
lfCharSet := ANSI_CharSet;
lfOutPrecision := Out_Default_Precis;
lfClipPrecision := Clip_Default_Precis;
lfQuality := Default_Quality;
lfPitchAndFamily := Variable_Pitch or ff_Swiss;
StrCopy(@FaceName, 'Helv');
end;
TheFont := CreateFontInderect(@MyLogFont);
end;
procedure MyWindow.MakeFont;
var
MyLogFont: TLogFont;
begin
with MyLogFont do
begin
lfHight := 10;
lfWidht := 0;
lfEscapement := 0;
lfOrientation := 0;
lfWeight := fw_Normal;
lfItalic := Ord(True);
lfUnderline := Ord(True);
lfStrikeOut := 0;
lfCharSet := ANSI_CharSet;
lfOutPrecision := Out_Default_Precis;
lfClipPrecision := Clip_Default_Precis;
lfQuality := Default_Quality;
lfPitchAndFamily := Fixed_Pitch or ff_DontCare;
StrCopy(@FaceName, 'Courier');
end;
TheFont := CreateFontInderect(@MyLogFont);
end;
procedure MyWindow.MakeFont;
var
MyLogFont: TLogFont;
begin
with MyLogFont do
begin
lfHight:=30;
lfWidht:=0;
lfEscapement:=0;
lfOrientation:=0;
lfWeight:=fw_Normal;
lfItalic:=0;
lfUnderline:=0;
lfStrikeOut:=0;
lfCharSet:=Symbol_CharSet;
lfOutPrecision:=Out_Default_Precis;
lfClipPrecision:=Clip_Default_Precis;
lfQuality:=Proof_Quality;
lfPitchAndFamily:=Fixed_Pitch or ff_Roman;
StrCopy(@FaceName, 'Rmn');
end;
TheFont:=CreateFontInderect(@MyLogFont);
end;
Использование изобразительных инструментальных средств
var
NewPen, OldPen: HPen;
TheDC: HDC;
begin
{ задать ширину пера 10 }
NewPen := CreatePen(ps_Solid, 10, RGB(0, 0, 0));
TheDC := GetDC(AWindow^.HWindow);
OldPen := SelectObject(TheDC, NewPen);
{ выполнить черчение }
SelectObject(TheDC, OldPen);
ReleaseDC(AWindow^.HWindow, TheDC);
DeleteObject(NewPen);
end;
ThePen:=GetStockObject(Black_Pen);
procedure SampleWindow.ChangePenToBlue;
var
ALogPen: TLogPen;
ThePen: HPen;
begin
ALogPen.lopnColor:=RGB(0, 0, 255);
ALogPen.lopnStyle:=ps_Solid;
ALogPen.lopnWidth.X:=0;
ALogPen.lopnWidth.Y:=0;
ThePen:=CreatePenInderect(@ALogPen);
SelectObject(TheDC, ThePen);
end;
Отображение графики в окнах
Изображение окон
Стратегия графики
Рисование в окнах
TheDC := GetDC(HWindow);
TextOut(TheDC, 50, 50, 'Sample Text', 11);
ReleaseDC(HWindow, TheDC);
Графические функции GDI
Функции изображения текста
procedure TMyWindow.Paint(PaintDC: HDC;
var PaintINfo: TPaintStruct);
var
MyTextString: array[0..20] of Char;
begin
StrCopy(MyTextString, 'Hello, World');
TextOut(PaintDC, 10, 15, MyTextString,
StrLen(MyTextString));
end;
Рис. 17.3 Результат выполнения функции TextOut.Функции рисования линий
procedure TMyWindow.Paint(PaintDC: HDC; var PaintINfo:
TPaintStruct);
begin
MoveTo(PaintDC, 100, 150);
LineTo(PaintDC, 10, 15);
end;
Рис. 17.4. Результат выполнения функции LineTo.
procedure TMyWindow.Paint(PaintDC: HDC; var PaintInfo:
TPaintStruct);
var
Points: array[0..2] of TPoint;
begin
Points[0].X:=10;
Points[0].Y:=15;
Points[1].X:=10;
Points[1].Y:=150;
Points[2].X:=100;
Points[2].Y:=150;
Polyline(PaintDC, @Points, 3);
end;
procedure TMyWindow.Paint(PaintDC: HDC;
var PaintInfo: TPaintStruct);
begin
Arc(PaintDC, 10, 10, 40, 40, 50, 0, 0, 0);
end;
Изображение фигур
Rectangle(PaintDC, 10, 15, 100, 150);
Рис. 17.6. Результат выполнения функции Rectangle.
RoundRect(PaintDC, 10, 15, 100, 150, 9, 11);
Ellipse(PaintDC, 10, 50, 100, 150);
Pie(PaintDC, 10, 10, 40, 40, 50, 0, 0, 0);
Chord(PaintDC, 10, 10, 40, 40, 50, 0, 0, 0);
procedure TMyWindow.Paint(PaintDC: HDC;
var PaintInfo: TPaintStruct);
var
Points: array[0..2] of TPoint;
begin
Points[0].X:=10;
Points[0].Y:=15;
Points[1].X:=10;
Points[1].Y:=150;
Points[2].X:=100;
Points[2].Y:=150;
Polygon(PaintDC, @Points, 3);
end;
Рис. 17.7. Результат выполнения функции Polygon.Использование палитр
Установка палитры
ThePalette := CreatePalette(@ALogPalette);
SelectPalette(TheDC, ThePalette, 0);
RealizePalette(TheDC);
Рисование с палитрами
ALogPen.lopnColor := $01000009;
Запрос палитры