Графический интерфейс GDI в Microsoft Windows

         

Атрибуты контекста отображения


В документации, которая поставляется в составе Microsoft SDK, описаны 20 атрибутов контекста отображения . Несколько атрибутов описывают систему координат, используемую для рисования графических изображений. Есть атрибуты, влияющие на цвет графических объектов и цвет фона. Для отображения можно выбрать цветовую палитру (набор цветов). Можно выбрать инструмент для рисования линий и закрашивания внутренней области замкнутых геометрических фигур, таких как многоугольники и эллипсы. Приложение может рисовать внутри области произвольной формы (или вне этой области), причем область также задается в контексте отображения. Есть атрибуты, специально предназначенные для вывода текста. Это шрифт и расстояние между символами, а также цвет текста.

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



Битовые изображения


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

В битовом изображении bitmap каждый пиксел представлен своим цветом. Есть черно-белые и цветные изображения, изображения, рассчитанные на определенный тип устройства вывода (использовались в ранних версиях Windows) и не зависящие от типа устройства вывода (впервые появились в Windows версии 3.0).

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

Работа с битовыми изображениями - не самое простое из того, что может быть в программировании для Windows. Особенно это касается использования битовых изображений в формате, не зависящем от типа устройства вывода или содержащих цветовые палитры. Ситуация дополнительно усложняется отсутствием единого формата bmp-файлов, содержащих изображения и необходимостью (в профессиональных приложениях) распознавать bmp-файлы, подготовленные в операционной системе OS/2, а также контролировать формат bmp-файлов. Однако только битовые изображения дают возможность получить на экране компьютера красивые рисунки, приближающиеся (на хороших мониторах) по качеству к слайдам, а также работать с движущимися изображениями.


Создавая приложение, которое должно работать с bmp-файлами, следует учитывать, что существует несколько форматов таких файлов. Файлы битовых изображений могут содержать таблицу цветов или цветовую палитру, могут быть сжаты с использованием алгоритмов RLE4 или RLE8 . Кроме того, коммерческая версия приложения должна уметь работать с битовыми изображениями в формате оболочки Presentation Manager операционной системы OS/2. Было бы также неплохо, если бы приложение могло анализировать структуру bmp-файла с целью обнаружения возможных ошибок, так как отображение содержимого неправильного файла может создать полный хаос на экране.

Кроме битовых изображений используются так называемые векторные изображения. Если битовые изображения содержат описание цвета каждого пиксела, векторные изображения состоят из описаний отдельных графических объектов, из которых состоит изображение. Это могут быть линии, окружности и т.п. Некоторые графические редакторы, например, Corel Draw, Microsoft Draw, Micrografx Designer, для внешнего представления изображения используют векторный формат.

Сравнивая эти форматы, отметим, что каждый из них имеет свои преимущества и свои недостатки.

Битовые изображения, как правило, выводятся на экран быстрее, так как их внутренняя структура аналогична (до некоторой степени) структуре видеопамяти. Изображения, получаемые при помощи сканеров и цифровых видеокамер (таких, как PhotoMan фирмы Logitec) получаются именно как битовые изображения.

К недостаткам битовых изображений можно отнести большой объем памяти, требующийся для их хранения (около 1 Мбайт в режиме True Color), невозможность масштабирования без потери качества изображения, а также сложность выделения и изменения отдельных объектов изображения.

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

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

Существует множество форматов файлов, предназначенных для хранения битовых и векторных изображений. В этой главе мы будем подробно рассматривать только формат файлов с расширением имени bmp (мы будем называть их bmp-файлами). Эти файлы хранят битовые изображения и используются в различных версиях операционной системы Microsoft Windows, Microsoft Windows NT и в графической оболочке Presentation Manager операционной системы OS/2. Векторные изображения можно хранить в виде метафайлов.


Битовые изображения в формате DDB




Как мы уже говорили, битовые изображения в формате DDB являются аппаратно-зависимыми. Поэтому структура изображения в оперативной памяти зависит от особенностей аппаратуры.

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

Как правило, изображения DDB либо загружаются из ресурсов приложения, либо создаются непосредственно в оперативной памяти. Для вывода изображений DDB на экран используются такие функции, как BitBlt и StretchBlt.

Изображения DIB, в отличие от изображений DDB, являются аппаратно-независимыми, поэтому без дополнительного преобразования их нельзя отображать на экране с помощью функций BitBlt и StretchBlt. В операционной системе Windows версий 3.х битовые изображения хранятся в файлах с расширением имени bmp, при этом используется аппаратно-независимый формат DIB.



Битовые изображения в формате DIB


Как мы уже говорили, битовые изображения DDB имеют один существенный недостаток - они "привязаны" к конкретному типу устройства вывода. В графической оболочке Presentation Manager операционной системы OS/2 впервые был использован аппаратно-независимый формат для хранения изображений, который называется DIB.

В операционной системе Windows версии 3.0 этот формат получил свое дальнейшее развитие. В частности, была добавлена возможность хранения изображения в компрессованном виде. К сожалению, использованный алгоритм компрессии дает хорошие результаты только для таких изображений, которые содержат большие одинаково закрашенные области. Операционная система Windows NT позволяет использовать новые форматы изображений DIB и произвольные методы компрессии, такие как, например, JPEG (очень эффективный метод компрессии графических изображений, при котором можно ценой потери качества получить практически любую степень сжатия).

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



Биты изображения


Формат области битов изображения одинаковый для некомпрессованых bmp-файлов Windows и bmp-файлов Presentation Manager (оболочка Presentation Manager операционной системы OS/2 версии 1.х не работает с компрессованными файлами).

Каждая строка битового изображения (scan line) хранится в буфере, длина которого кратна двойному слову DWORD. Для черно/белых изображений каждый бит буфера используется для представления цвета одного пиксела (если не используется компрессия).

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

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

В памяти изображение хранится в перевернутом виде. Поэтому, например, изображение, показанное на рис. 4.1 после вывода будет иметь вид, показанный на рис. 4.6.

Рис. 4.6. Изображение в окне Windows

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

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

dwSizeImage = ((nBits + 31)/32 * 4) * biHeight

где

nBits = biBitCount * biWidth

В этих формулах переменные biHeight, biBitCount и biWidth являются полями структуры BITMAPINFOHEADER.

Если же изображение хранится в компрессованом формате (в поле biCompression структуры BITMAPINFOHEADER находятся значения BI_RLE4 или BI_RLE8), нужный размер буфера можно получить из поля biSizeImage структуры BITMAPINFOHEADER.


Формат области битов изображения для цветных файлов сложнее, однако размер области определяется аналогично.

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

Но в большинстве случаев для вывода готового изображения от вас требуется только умение определить размер области битов изображения для получения соответствующего буфера, куда эта область загружается из bmp-файла перед выводом изображения на экран. Поэтому мы не будем рассматривать формат области битов изображения для цветных bmp-файлов. Отметим только, что для bmp-файлов в формате DIB для представления цвета одного пиксела используются несколько бит памяти. Например, в 16-цветных файлах цвет пиксела представляется при помощи 4 бит памяти, в 256-цветных файлах для этой цели используется 8 бит, файлы True Color используют 24 бита.


Цвет фона


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

Приложение может изменить цвет фона, воспользовавшись функцией SetBkColor . Мы опишем эту, а также другие функции, связанные с цветом, в отдельной главе.



Цвет и цветовые палитры


3.1.

3.2.

3.3.

3.4.

3.5.

3.6.

До сих пор мы в наших приложениях практически не использовали цвет. Теперь настало время рассказать о том, как с помощью средств GDI можно раскрасить окна ваших приложений.

Не секрет, что цветовые возможности приложений ограничиваются в основном цветовым разрешением аппаратуры. В настоящее время чаще всего используются монохромные видеомониторы VGA (как правило, в портативных компьютерах типа Notebook), цветные видеомониторы VGA и SVGA. Все реже встречаются видеомониторы EGA и CGA, которые мало подходят для работы в Windows.

При использовании монохромных мониторов VGA вместо цветов используются градации серого, поэтому приложения не ограничены в выборе черным и белым цветами. Для мониторов EGA и VGA в распоряжении приложений Windows имеется всего лишь 16 цветов.

Цветовое разрешение для мониторов SVGA зависит от типа видеоконтроллера и от объема установленной в нем видеопамяти. Обычные видеоконтроллеры SVGA могут отображать одновременно только 256 цветов. Самые хорошие видеоконтроллеры SVGA, способные работать в режиме True Color , могут отображать 16,777,216 цветов. Это достаточно много, хотя цветовое разрешение человеческого глаза еще выше.

Для использования режимов с высоким разрешением необходимо использовать драйверы, которые обычно поставляются вместе с видеоконтроллерами. Приведем возможные режимы работы для драйверов Cirrus 542x версии 1.0, которые поставляются с видеоконтроллерами на базе видеопроцессоров фирмы Cirrus Logic при объеме видеопамяти 1 Мбайт:

Разрешение в пикселах Цветовое разрешение
1024x768 16
1024x768 256
800x600 16
800x600 256
800x600 65,536
640x480 16
640x480 256
640x480 65,536
640x480 16,777,216

В нашей книге разрешение 16 цветов мы будем называть низким цветовым разрешением, 256 цветов - средним, 65,536 и 16,777,216 цветов - высоким.

В операционной системе Windows приложения определяют цвет, задавая интенсивности трех его RGB-компонент: красной (R), зеленой (G) и голубой (B).
Интенсивность каждой компоненты задается числом в диапазоне от 0 (минимальная интенсивность) до 255 (максимальная интенсивность). Такая система позволяет приложению указать любой из 16,777,216 цветов (256*256*256 = 16,777,216).

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

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

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

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

В режиме True Color палитры не используются, а полученный на экране цвет изображения в точности соответствует заказанному.

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

Поэтому когда пользователю не нужна высокая скорость работы в Windows, но нужна возможность работы с разрешением 256 цветов, он может остановить свой выбор на более дешевом видеоконтроллере.Кроме того, даже если в компьютере установлен видеоадаптер True Color, он может использоваться в режимах со средним или низким цветовым разрешением. Для программиста это означает необходимость использования цветовых палитр, так как только в этом случае будут реализованы все цветовые возможности такого видеоконтроллера.


Цвет текста


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

Для выбора цвета текста приложение должно использовать функцию SetTextColor .



Цветовая палитра


Цветовая палитра (color palette ) - это таблица цветов. Некоторые устройства отображения способны работать с десятками тысяч цветов, однако из-за ограничений аппаратуры в них можно использовать одновременно только некоторые из них. Типичный пример - видеоконтроллеры SVGA в режиме отображения 256 цветов. Приложения Windows могут составить для себя палитру из 236 цветов (20 цветов используются системой) и использовать ее для вывода таких изображений, как, например, цветные фотографии, преобразованные в двоичные данные при помощи сканера.

Использование цветовых палитр мы рассмотрим позже. Отметим только, что работа с палитрами - сложная задача, требующая учета многочисленных тонкостей. Современные адаптеры True Color способны отображать более 16 млн. цветов одновременно, поэтому для них механизм цветовых палитр не используется.

Для работы с палитрами в составе программного интерфейса определены такие функции, как CreatePalette , SelectPalette , RealizePalette , UnrealizeObject .



DIBCreatePalette


Функция создает логическую палитру на базе таблицы цветов изображения DIB, возвращая идентификатор созданной палитры или NULL при ошибке. Если DIB не содержит таблицу цветов, палитра не создается.

Прототипы всех описанных выше функций, а также необходимые константы и типы данных описаны в файле dib.hpp (листинг 4.9).

Листинг 4.9. Файл bmpinfo/dib.hpp

#define WINRGB_DIB 1 #define WINRLE4_DIB 2 #define WINRLE8_DIB 3 #define PM_DIB 10

typedef HGLOBAL HDIB; typedef unsigned char huge* LPDIB;

HFILE DIBSelectFile(void); HDIB DIBReadFile(HFILE hfDIBFile, DWORD *dwFileSize); BOOL DIBInfo(HDIB hDib, DWORD dwFileSize); int DIBType(HDIB hDib); WORD DIBNumColors(LPDIB lpDib); WORD DIBHeight(LPDIB lpDib); WORD DIBWidth(LPDIB lpDib); HPALETTE DIBCreatePalette(HDIB hDIB); BOOL DIBPaint(HDC hDC, int x, int y, HDIB hDIB);

Обратите внимание на тип LPDIB, который описан как указатель типа huge:

typedef unsigned char huge* LPDIB;

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

Файл определения ресурсов приложения BMPINFO приведен в листинге 4.10.

Листинг 4.10. Файл bmpinfo/bmpinfo.rc

#include "bmpinfo.hpp"

APP_MENU MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Open", CM_FILEOPEN MENUITEM "&Info...", CM_FILEINFO MENUITEM SEPARATOR MENUITEM "E&xit", CM_FILEEXIT END

POPUP "&Help" BEGIN MENUITEM "&About...", CM_HELPABOUT END END

Файл определения модуля приложения BMPINFO вы сможете найти в листинге 4.11.

Листинг 4.11. Файл bmpinfo/bmpinfo.def

; ============================= ; Файл определения модуля ; ============================= NAME BMPINFO DESCRIPTION 'Приложение BMPINFO, (C) 1994, Frolov A.V.' EXETYPE windows STUB 'winstub.exe' STACKSIZE 8120 HEAPSIZE 1024 CODE preload moveable discardable DATA preload moveable multiple



DIBFindBits


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



DIBHeight


Функция возвращает высоту изображения DIB в пикселах как значение поля biHeight структуры BITMAPINFOHEADER.



DIBInfo


Функция выводит информацию о загруженном изображении DIB. Идентификатор блока памяти, содержащего файл изображения, передается этой функции в качестве первого параметра. Через второй параметр передается размер файла, определенный функцией чтения файла DIBReadFile.



DIBNumColors


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



DIBPaint


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

Рисование выполняется при помощи функции StretchDIBits.



DIBPaintBlt


Функция аналогична предыдущей, однако перед рисованием выполняется преобразование DIB в DDB. Далее преобразованное изображение выводится через контекст памяти в контекст отображения при помощи функции BitBlt.



DIBReadFile


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

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

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

Так как размер bmp-файлов обычно больше 64 Кбайт, для чтения используется функция _hread.



DIBSelectFile


Эта функция выводит на экран стандартную диалоговую панель "Open", с помощью которой можно выбрать bmp-файл.

Функция возвращает идентификатор открытого файла или NULL, если пользователь отказался от выбора.



DIBType


Функция получает в качестве параметра идентификатор блока памяти, содержащего загруженный файл изображения DIB. Она определяет его формат и выполняет проверку полей структур заголовка.

Если в качестве параметра этой функции было передано значение NULL, она возвращает код ошибки-2. Если не удалось зафиксировать блок памяти, возвращается код ошибки -1.

Функция проверяет первые два байта bmp-файла. Если они не содержат значения 0x4d42, возвращается код ошибки 0.

Далее функция определяет формат заголовка. Для изображения в стандарте Windows проверяются поля biPlanes, biBitCount и biCompression структуры BITMAPINFOHEADER, а для изображения в стандарте Presentation Manager - поля biPlanes и biBitCount структуры BITMAPCOREHEADER.



DIBWidth


Функция возвращает ширину изображения DIB в пикселах как значение поля biWidth структуры BITMAPINFOHEADER.



Другие функции для работы с изображениями DDB


Если вы создали изображение DDB, то пользуясь его идентификатором, нетрудно скопировать в него новый массив бит, соответствующий новому изображению. Для этой цели можно воспользоваться функцией SetBitmapBits :

LONG WINAPI SetBitmapBits( HBITMAP hbmp, DWORD cBits, const void FAR* lpvBits);

Первый параметр этой функции предназначен для передачи идентификатора битового изображения. Параметр lpvBits является указателем на массив бит, размер этого массива задается при помощи параметра cBits.

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

Обратную операцию (чтение массива памяти изображения) можно выполнить при помощи функции GetBitmapBits :

LONG WINAPI GetBitmapBits( HBITMAP hbmp, LONG cbBuffer, void FAR* lpvBits);

Эта функция копирует байты изображения hbmp в массив lpvBits, причем размер массива указывается через параметр cbBuffer.

Функция возвращает количество скопированных в буфер байт в случае нормального завершения или нулевое значение при ошибке.

Если вам нужно создать цветное битовое изображение DDB, можно воспользоваться функцией CreateCompatibleBitmap :

HBITMAP WINAPI CreateCompatibleBitmap( HDC hdc, // контекст отображения int nWidth, // ширина изображения int nHeight); // высота изображения

Эта функция создает неинициализированное изображение шириной nWidth пикселов и высотой nHeight пикселов, причем формат изображения соответствует контексту отображения hdc.

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

Если желательно создать удаляемое (discardable) битовое изображение, вместо предыдущей функции вы можете вызвать функцию CreateDiscardableBitmap :

HBITMAP WINAPI CreateDiscardableBitmap( HDC hdc, // контекст отображения int nWidth, // ширина изображения int nHeight); // высота изображения

Она имеет параметры, аналогичные параметрам функции CreateCompatibleBitmap. Если изображение, созданное с использованием этой функции, не выбрано в контекст памяти, оно может быть удалено. При попытке выбрать в контекст удаленное изображение функция SelectBitmap вернет нулевое значение. В этом случае необходимо удалить изображение макрокомандой DeleteBitmap, после чего создать его заново.



Другие операции


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

void WINAPI SetRectRgn( HRGN hrgn, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);

Изменение области выполняется быстрее ее удаления с последующим повторный созданием новой.

Для перемещения области предназначена функция OffsetRgn :

int WINAPI OffsetRgn(HRGN hrgn, int nX, int nY);

Эта функция сдвигает область на nX логических единиц по горизонтали и на nY логических единиц по вертикали, возвращая такие же значения, что и функция CombineRegion.

Вы можете сравнить две области при помощи функции EqualRgn :

BOOL WINAPI EqualRgn(HRGN hrgn1, HRGN hrgn2);

Эта функция возвращает TRUE, если области совпадают, и FALSE - если нет.

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

int WINAPI GetRgnBox(HRGN hrgn, RECT FAR* lprc);

Эта функция возвращает такие же значения, что и функция CombineRegion

Иногда требуется определить, находится ли заданная точка или прямоугольная область внутри другой области. Это можно сделать при помощи функций PtInRegion и RectInRegion .

Функция PtInRegion возвращает TRUE, если точка (nX,nY) находится внутри области hrgn:

BOOL WINAPI PtInRegion(HRGN hrgn, int nX, int nY);

Аналогично для прямоугольной области:

BOOL WINAPI RectInRegion(HRGN hrgn, const RECT FAR* lprc);



Физическая система координат


На рис. 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 800x 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 ), и, что самое главное, отношение высоты и ширины пиксела также зависят от типа видеоконтроллера.

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



Flags


Это поле должно содержать флаги инициализации:

PD_ALLPAGES

Переключатель "All" в диалоговой панели "Print" должен находиться во включенном состоянии, при этом предполагается что необходимо распечатать весь текст, а не отдельные страницы или выделенный фрагмент текста.

PD_SELECTION

Переключатель "Selection" в диалоговой панели "Print" должен находиться во включенном состоянии, при этом предполагается что необходимо распечатать выделенный фрагмент текста, но не весь текст или отдельные страницы.

PD_PAGENUMS

Переключатель "Page" в диалоговой панели "Print" должен находиться во включенном состоянии, при этом предполагается что необходимо распечатать отдельные страницы текста, но не выделенный фрагмент текста или весь текст.

PD_NOSELECTION

Переключатель "Selection" должен находиться в заблокированном состоянии.

PD_NOPAGENUMS

Переключатель "Pages" и связанные с ним органы управления должны находиться в заблокированном состоянии.

PD_COLLATE

Переключатель "Collate" должен находиться во включенном состоянии.

PD_PRINTTOFILE

Переключатель "Print to File" должен находиться во включенном состоянии.

PD_PRINTSETUP

При вызове функции PrintDlg вместо диалоговой панели "Print" отображается диалоговая панель "Print Setup".

PD_NOWARNING

Отмена вывода сообщения о том, что в системе не установлен принтер по умолчанию.

PD_RETURNDC

Функция PrintDlg должна вернуть в поле hDC идентификатор контекста устройства, который можно использовать для печати.

PD_RETURNIC

Функция PrintDlg должна вернуть в поле hDC идентификатор информационного контекста, который можно использовать для получения информации о принтере.

PD_RETURNDEFAULT

После возвращения из функции PrintDlg поля hDevMode и hDevNames будут содержать идентификаторы блоков памяти структур DEVMODE и DEVNAMES, заполненных параметрами принтера, выбранного по умолчанию. Если указан флаг PD_RETURNDEFAULT, перед вызовом функции PrintDlg поля hDevMode и hDevNames должны содержать значения NULL, в противном случае функция вернет признак ошибки.


PD_SHOWHELP

В диалоговой панели необходимо отобразить кнопку "Help".

PD_ENABLEPRINTHOOK

Разрешается использовать функцию фильтра для диалоговой панели "Print".

PD_ENABLESETUPHOOK

Разрешается использовать функцию фильтра для диалоговой панели "Print Setup".

PD_ENABLEPRINTTEMPLATE

Разрешается использовать шаблон диалоговой панели "Print", определяемой полями hInstance и lpPrintTemplateName.

PD_ENABLESETUPTEMPLATE

Разрешается использовать шаблон диалоговой панели "Print Setup", определяемой полями hInstance и lpSetupTemplateName.

PD_ENABLEPRINTTEMPLATEHANDLE

Поле hPrintTemplate содержит идентификатор блока памяти с загруженным шаблоном диалоговой панели "Print". Содержимое поля hInstance игнорируется.

PD_ENABLESETUPTEMPLATEHANDLE

Поле hSetupTemplate содержит идентификатор блока памяти с загруженным шаблоном диалоговой панели "Print Setup". Содержимое поля hInstance игнорируется.

PD_USEDEVMODECOPIES

Орган управления "Copies" блокируется, если принтерный драйвер не способен печатать несколько копий.

PD_DISABLEPRINTTOFILE

Блокируется переключатель "Print to File".

PD_HIDEPRINTTOFILE

Переключатель "Print to File" блокируется и удаляется из диалоговой панели.


Формат bmp-файлов Presentation Manager


Оболочка Presentation Manager операционной системы OS/2 использует другой формат bmp-файла (рис. 4.5).

Рис. 4.5. Формат bmp-файла для Presentaton Manager операционной системы OS/2 версии 1.х

В самом начале файла расположена структура BITMAPFILEHEADER. Ее формат полностью соответствует формату аналогичной структуры bmp-файлов операционной системы Windows. В этой структуре, в частности, есть информация о смещении области битов изображения относительно начала файла.

После структуры BITMAPFILEHEADER в файле располагается структура BITMAPCOREINFO, содержащая структуру BITMAPCOREHEADER и таблицу цветов в виде массива структур RGBTRIPLE :

typedef struct tagBITMAPCOREINFO { BITMAPCOREHEADER bmciHeader; RGBTRIPLE bmciColors[1]; } BITMAPCOREINFO; typedef BITMAPCOREINFO* PBITMAPCOREINFO; typedef BITMAPCOREINFO FAR* LPBITMAPCOREINFO;

Формат структуры BITMAPCOREHEADER приведен ниже:

typedef struct tagBITMAPCOREHEADER { DWORD bcSize; short bcWidth; short bcHeight; WORD bcPlanes; WORD bcBitCount; } BITMAPCOREHEADER; typedef BITMAPCOREHEADER* PBITMAPCOREHEADER; typedef BITMAPCOREHEADER FAR* LPBITMAPCOREHEADER;

Приведем описание отдельных полей этой структуры.

Поле Описание
bcSize Размер структуры BITMAPCOREHEADER в байтах
bcWidth Ширина битового изображения в пикселах
bcHeight Высота битового изображения в пикселах
bcPlanes Количество плоскостей в битовом изображении. Содержимое этого поля должно быть равно 1
bcBitCount Количество битов на один пиксел. Может быть равно 1, 4, 8 или 24

Таблица цветов в bmp-файле в формате Presentation Manager расположена после структуры BITMAPCOREHEADER и представляет собой массив структур RGBTRIPLE , содержащих RGB-компоненты цвета:

typedef struct tagRGBTRIPLE { BYTE rgbtBlue; BYTE rgbtGreen; BYTE rgbtRed; } RGBTRIPLE; typedef RGBTRIPLE FAR* LPRGBTRIPLE;

Зная количество битов, используемых для представления одного пиксела изображения, нетрудно определить количество элементов в таблице цветов:

wClrUsed = 1 << bcBitCount;



Формат bmp-файлов Windows


Формат bmp-файлов для операционной системы Windows версий 3.0 и 3.1 представлен на рис. 4.4 (в более старых версиях bmp-файлы содержали битовые изображения в формате DDB).

Рис. 4.4. Формат bmp-файла для Windows версии 3.х

Файл, содержащий битовое изображение, начинается со структуры BITMAPFILEHEADER. Эта структура описывает тип файла и его размер, а также смещение области битов изображения.

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

Биты изображения обычно располагаются сразу после таблицы цветов. Точное значение смещения битов изображения находится в структуре BITMAPFILEHEADER.

Структура BITMAPFILEHEADER , а также указатели на нее, описаны в файле windows.h:

typedef struct tagBITMAPFILEHEADER { UINT bfType; DWORD bfSize; UINT bfReserved1; UINT bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER; typedef BITMAPFILEHEADER* PBITMAPFILEHEADER; typedef BITMAPFILEHEADER FAR* LPBITMAPFILEHEADER;

Структура BITMAPFILEHEADER одинакова как для bmp-файлов Windows, так и для bmp-файлов оболочки Presentation Manager (рис. 4.5). И в том, и в другом случае она расположена в начале файла и обычно используется для идентификации типа файла.

Приведем описание полей этой структуры.

Поле Описание
bfType Тип файла. Поле содержит значение 0x4D42 (текстовая строка "BM"). Анализируя содержимое этого поля, приложение может идентифицировать файл как содержащий битовое изображение
bfSize Размер файла в байтах. Это поле может содержать неправильное значение, так как в SDK для Windows версии 3.0 поле bfSize было описано неправильно (утверждалось, что это поле содержит размер файла в двойных словах). Обычно содержимое этого поля игнорируется, так как из-за ошибки в документации старые приложения устанавливали в этом поле неправильное значение
bfReserved1 Зарезервировано, должно быть равно 0
bfReserved2 Зарезервировано, должно быть равно 0
bfOffBits Смещение битов изображения от начала файла в байтах. Область изображения не обязательно должна быть расположена сразу вслед за заголовками файла или таблицей цветов (если она есть)
<
В структуре BITMAPFILEHEADER для нас важны два поля - поле bfType, определяющее тип файла, и поле bfOffBits, определяющее смещение битов, из которых формируется изображение. Остальные поля можно проигнорировать. В частности, размер файла нетрудно определить средствами файловой системы MS-DOS.

Сразу после структуры BITMAPFILEHEADER в bmp-файле расположена структура BITMAPINFO (для изображений Windows) или BITMAPCOREINFO (для изображений Presentation Manager).

Структура BITMAPINFO и указатели на нее описаны в файле windows.h следующим образом:

typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO; typedef BITMAPINFO* PBITMAPINFO; typedef BITMAPINFO FAR* LPBITMAPINFO;

Структура BITMAPINFOHEADER описывает размеры и способ представления цвета в битовом изображении:

typedef struct tagBITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER; typedef BITMAPINFOHEADER* PBITMAPINFOHEADER; typedef BITMAPINFOHEADER FAR* LPBITMAPINFOHEADER;

Опишем назначение отдельных полей этой структуры.

Поле Описание
biSize Размер структуры BITMAPINFOHEADER в байтах
biWidth Ширина битового изображения в пикселах
biHeight Высота битового изображения в пикселах
biPlanes Количество плоскостей в битовом изображении. Содержимое этого поля должно быть равно 1
biBitCount Количество битов на один пиксел. Может быть равно 1, 4, 8 или 24. Для новых 16- и 32-битовых форматов файлов DIB, используемых в Windows NT, в этом поле могут находиться также значения 16 и 32
biCompression Метод компрессии. Может принимать одно из следующих значений:BI_RGB - компрессия не используетсяBI_RLE4 - компрессия изображений, в которых для представления пиксела используется 4 бита. При использовании этого метода компрессии содержимое поля biBitCount должно быть равно 4BI_RLE8 - компрессия изображений, в которых для представления пиксела используется 8 бит. При использовании этого метода компрессии содержимое поля biBitCount должно быть равно 8BI_BITFIELDS - другой формат компрессии. Это значение используется для Windows NT. Соответствующая константа описана в файле windows.h, который поставляется вместе со средствами разработки приложений Windows NT
biSizeImage Размер изображения в байтах. Это поле содержит размер, необходимый для хранения разжатого изображения. Если компрессия не используется (в поле biCompression находится значение BI_RGB), содержимое поля biSizeImage может быть равно 0
biXPelsPerMeter Разрешение устройства вывода по горизонтали в пикселах на метр, необходимое для вывода битового изображения без искажений. Это поле используется не всегда. Если оно не используется, в нем следует установить нулевое значение.
biYPelsPerMeter Разрешение устройства вывода по вертикали в пикселах на метр, необходимое для вывода битового изображения без искажений. Это поле, как и предыдущее, используется не всегда. Если оно не используется, в нем следует установить нулевое значение
biClrUsed Размер таблицы цветов. Это поле определяет размер массива структур RGBQUAD (рис. 4.4), расположенного в файле сразу после структуры BITMAPINFOHEADER. Если в этом поле находится нулевое значение, размер таблицы цветов зависит от количества бит, используемых для представления цвета одного пиксела (поле biBitCount)
biClrImportant Количество цветов, необходимое для отображения файла без искажений. Обычно в этом поле находится нулевое значение, в этом случае важны все цвета
<


Сразу после структуры BITMAPINFOHEADER в фале может находиться таблица цветов. Эта таблица содержит массив структур RGBQUAD :

typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD; typedef RGBQUAD FAR* LPRGBQUAD;

Поля rgbBlue, rgbGreen и rgbRed содержат RGB-компоненты цветов, поле rgbReserved зарезервировано и должно содержать нулевое значение.

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

Значение biBitCount Размер таблицы цветов
1 2
4 16
8 256
24 не используется
Если содержимое поля biClrUsed отлично от нуля, используется таблица цветов уменьшенного размера. В ней описаны только те цвета, которые содержатся в изображении.


Форматы файлов и структур данных


Если рассматривать структуру bmp-файлов в общем, для нас интересны два формата. Первый формат используется в Windows версий 3.х, второй - в графической оболочке Presentation Manager операционной системы OS/2 версий 1.х. Первый из этих форматов является естественным для приложений Windows. Что же касается второго формата, такие приложения, как Paint Brush, способны конвертировать его в стандартный формат Windows.

Ваше приложение может либо полностью проигнорировать формат bmp-файлов оболочки Presentation Manager, либо (что лучше) автоматически преобразовывать его к формату Windows, как это делают стандартные приложения Windows.



Функции для печати


В операционной системе Windows версии 3.0 и более ранних версий для печати использовалась одна функция Escape, которая имела множество подфункций (63 подфункции). Начиная с версии 3.1 вместо этой функции рекомендуется использовать несколько других.

Чаще всего используются семь функций.

StartDoc

Эта функция начинает печать нового документа (формирует задание на печать). Она должна вызываться один раз перед началом печати нового документа

StartPage

Эта функция подготавливает устройство вывода к печати новой страницы документа. После вызова этой функции приложение может начинать печать, используя контекст принтера.

EndPage

Функция EndPage завершает процесс печати страницы. Метафайл, созданный в процессе печати одной страницы, проигрывается на принтере.

EndDoc

Функция завершает процесс печати документа. Она вызывается один раз после завершения печати документа.

AbortDoc

Эта функция предназначена для аварийного завершения процесса печати документа.

SetAbortProc

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

ResetDC

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

Как пользоваться этими функциями?

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

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

Приведем прототип функции SetAbortProc :

int SetAbortProc(HDC hdc, ABORTPROC abrtprc);

Первый параметр определяет контекст устройства, для которого устанавливается функция отмены печати, второй - адрес функции отмены печати, полученный при помощи функции MakeProcInstance .

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


BOOL CALLBACK _export AbortFunc(HDC hdc, int nCode) { MSG msg; while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { if(!hdlgAbort !IsDialogMessage(hdlgAbort, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return(!fAbort); }

В качестве первого параметра функции передается контекст устройства, в качестве второго - код ошибки. Однако обычно оба эти параметра игнорируются.

GDI в процессе печати периодически вызывает функцию отмены печати, которая действует аналогично обычному циклу обработки сообщений, выполняя выборку сообщений из очереди и их диспетчеризацию. Если в очереди больше нет сообщений, функция PeekMessage возвращает FALSE, при этом цикл обработки сообщений завершается.

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

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

BOOL CALLBACK _export AbortDlgFunc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_INITDIALOG: { fAbort = FALSE; hdlgAbort = hdlg; return TRUE; } case WM_COMMAND: { if (wParam == IDOK wParam == IDCANCEL) { fAbort = TRUE; return TRUE; } return FALSE; } case WM_DESTROY: { hdlgAbort = 0; return FALSE; } } return FALSE; }

Основной задачей данной функции является установка глобального флага отмены печати fAbort:

fAbort = TRUE;

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

Прежде всего необходимо вызвать функцию StartDoc :

int StartDoc( HDC hdc, // контекст принтера DOCINFO FAR* lpdi); // адрес структуры DOCINFO

Перед вызовом этой функции нужно подготовить структуру DOCINFO , адрес которой передается через параметр lpdi:

typedef struct { int cbSize; LPCSTR lpszDocName; LPCSTR lpszOutput; } DOCINFO;



Поле cbSize должно содержать размер структуры в байтах.

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

Через поле lpszOutput можно передать адрес строки, содержащей имя файла (если печать должна быть переназначена в файл). Поле может содержать NULL, в этом случае выполняется печать на принтере.

Далее можно начинать цикл печати страниц документа.

Печать страницы документа начинается с вызова функции StartPage :

int StartPage(HDC hdc);

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

После вызова функции StartPage приложение может начинать печать страницы, вызывая обычные функции GDI, такие как TextOut, BitBlt, StretchBlt, Rectangle и т. п.

Завершив печать одной страницы, приложение должно вызвать функцию EndPage :

int EndPage(HDC hdc);

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

При успешном завершении функция возвращает положительное значение, отличное от нуля, при ошибке - нуль или значение, меньшее нуля

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

После успешной печати всех страниц документа нужно вызвать функцию EndDoc :

int EndDoc(HDC hdc);

Если печать была отменена, или произошла ошибка, вместо этой функции следует вызвать функцию AbortDoc :

int AbortDoc(HDC hdc);

Если в процессе печати нужно изменить параметры принтера для отдельных страниц документа, вы можете вызвать до функции StartPage функцию ResetDC :

HDC ResetDC( HDC hdc, // контекст печати const DEVMODE FAR* lpdm); // адрес структуры DEVMODE

Эта функция изменяет контекст печати на основе информации, представленной в структуре DEVMODE.

Приложение обычно вызывает эту функцию также в ответ на сообщение WM_DEVMODECHANGE, которое посылается приложению при изменении параметров принтера.

Учтите, что функция StartPage запрещает изменение контекста печати, поэтому вы не сможете изменить параметры печати в процессе печати страницы.


Функция ChooseColor


В составе DLL-библиотеки commdlg.dll есть функция ChooseColor , которая предназначена для выбора цвета . Эта функция выводит на экран диалоговую панель (рис. 3.3), с помощью которой пользователь может выбрать цвет из основного набора цветов "Basic Color" и дополнительного "Custom Colors". Возможность использования цветовых палитр при выборе не обеспечивается, так что с помощью этой функции можно выбирать только чистые статические или смешанные цвета.

Рис. 3.3. Диалоговая панель для выбора цвета

Если нажать на кнопку "Define Custom Colors...", внешний вид диалоговой панели изменится (рис. 3.4).

Рис. 3.4. Расширенная диалоговая панель

Пользуясь правой половиной диалоговой панели, пользователь сможет добавить новый цвет в набор "Custom Colors" и затем выбрать его из этого набора.

Функция ChooseColor описана в файле commdlg.h:

BOOL WINAPI ChooseColor(CHOOSECOLOR FAR* lpcc);

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

В случае успешного выбора цвета функция возвращает TRUE. Если пользователь отказался от выбора или, если произошла ошибка, возвращается значение FALSE.

Структура CHOOSECOLOR и указатель на нее описаны в файле commdlg.h:

typedef struct tagCHOOSECOLOR { DWORD lStructSize; HWND hwndOwner; HWND hInstance; COLORREF rgbResult; COLORREF FAR* lpCustColors; DWORD Flags; LPARAM lCustData; UINT (CALLBACK* lpfnHook)(HWND, UINT, WPARAM, LPARAM); LPCSTR lpTemplateName; } CHOOSECOLOR; typedef CHOOSECOLOR FAR *LPCHOOSECOLOR;

Опишем назначение и правила использования отдельных полей этой структуры.

Поле lStructSize заполняется перед вызовом функции. Оно должно содержать размер структуры в байтах.

Поле Flags также заполняется до вызова функции. В него следует записать флаги инициализации, влияющие на использование других полей этой структуры.

Флаг Описание
CC_RGBINIT Для цвета, выбранного по умолчанию, используется цвет, указанный в поле rgbResult
CC_FULLOPEN Если указан этот флаг, на экране появляется полный вариант диалоговой панели, обеспечивающий возможность определения произвольного цвета. Если этот флаг не указан, для определения произвольного цвета пользователь должен нажать на кнопку "Define Custom Color"
CC_PREVENTFULLOPEN Кнопка "Define Custom Color" блокируется, таким образом, при использовании этого флага пользователь не может определить произвольный цвет
CC_SHOWHELP Флаг разрешает отображение кнопки "Help". Если указан этот флаг, в поле нельзя указывать значение hwndOwner
CC_ENABLEHOOK Если указан этот флаг, используется функция фильтра, адрес которой указан в поле lpfnHook. С помощью этой функции можно организовать дополнительную обработку сообщений от диалоговой панели
CC_ENABLETEMPLATE Используется шаблон диалоговой панели, определяемый содержимым поля hInstance. Адрес строки, содержащей имя шаблона, должен быть указан в поле lpTemplateName
CC_ENABLETEMPLATEHANDLE Используется шаблон диалоговой панели, идентификатор которого записан в поле hInstance. Содержимое поля lpTemplateName игнорируется
<
В поле hwndOwner перед вызовом функции следует записать идентификатор окна, создавшего диалоговую панель, или NULL. В последнем случае нельзя использовать флаг CC_SHOWHELP.

Поле hInstance заполняется в тех случаях, когда приложение использует свой собственный шаблон диалоговой панели (вместо стандартного шаблона, расположенного в ресурсах DLL-библиотеки). В этом случае перед вызовом функции в это поле следует записать идентификатор модуля, содержащего шаблон диалоговой панели. В поле Flags необходимо указать флаги CC_ENABLETEMPLATE или CC_ENABLETEMPLATEHANDLE.

В поле lpTemplateName следует записать адрес текстовой строки идентификатора ресурса шаблона диалоговой панели (если этот шаблон используется).

Поле rgbResult предназначено для передачи приложению цвета, выбранного пользователем. Если записать в это поле значение NULL, сразу после вывода диалоговой панели выбора цвета по умолчанию будет выбран черный цвет. Вы, однако, можете использовать для начального выбора любой другой цвет, записав его в это поле и указав флаг CC_RGBINIT.

Перед вызовом функции вы должны подготовить массив из 16 двойных слов, содержащих цвета для использования в меню "Custom Colors". Адрес этого массива следует передать через параметр lpCustColors.

Поле lCustData используется для передачи данных функции фильтра (если она определена).

Адрес функции фильтра передается через параметр lpfnHook. Для использования функции фильтра следует указать флаг CC_ENABLEHOOK.


Функция ChooseFont


Только что мы приближенно описали алгоритм, который используется GDI для отображения логического шрифта на физический. Нетрудно заметить, что приложение может получить от GDI совсем не тот шрифт, который ему нужен. Поэтому лучше всего предоставить пользователю возможность выбрать шрифт самостоятельно.

DLL-библиотека commdlg.dll содержит функцию ChooseFont , специально предназначенную для выбора одного из зарегистрированных в системе шрифтов. Эта функция выводит на экран диалоговую панель "Font", с помощью которой пользователь может выбрать шрифт, стиль шрифта, размер шрифта, цвет букв, может выбрать подчеркнутый или перечеркнутый шрифт (рис. 5.2).

Рис. 5.2. Диалоговая панель "Font"

Из списка "Font", который расположен в левой верхней части этой диалоговой панели, пользователь может выбрать название шрифта. Список "Font Style" позволяет выбрать один из доступных стилей, например, наклонный или жирный шрифт. Список "Size" предназначен для выбора размера шрифта. С помощью переключателей "Strikeout" и "Underline", расположенных в поле "Effects", можно создать, соответственно, перечеркнутый и подчеркнутый шрифт. И, наконец, из меню "Color" можно выбрать цвет букв.

Образец выбранного шрифта отображается в поле "Sample".

Обратите внимание на то, что в списке "Font" некоторые шрифты отмечены двойной буквой "T". Это масштабируемые шрифты True Type.

Приведем прототип функции ChooseFont:

BOOL WINAPI ChooseColor(CHOOSEFONT FAR* lpcf);

Единственный параметр функции является указателем на структуру типа CHOOSEFONT. Эта структура, а также сама функция ChooseFont, определены в файле commdlg.h. Структура определена следующим образом:

typedef struct tagCHOOSEFONT { DWORD lStructSize; HWND hwndOwner; HDC hDC; LOGFONT FAR* lpLogFont; int iPointSize; DWORD Flags; COLORREF rgbColors; LPARAM lCustData; UINT (CALLBACK* lpfnHook)(HWND, UINT, WPARAM, LPARAM); LPCSTR lpTemplateName; HINSTANCE hInstance; LPSTR lpszStyle; UINT nFontType; int nSizeMin; int nSizeMax; } CHOOSEFONT; typedef CHOOSEFONT FAR *LPCHOOSEFONT;


Перед вызовом функции ChooseFont вы должны проинициализировать нужные поля структуры CHOOSEFONT, записав в остальные поля нулевые значения.

Опишем назначение отдельных полей структуры CHOOSEFONT:

Поле Описание
lStructSize Размер структуры в байтах. Это поле необходимо заполнить перед вызовом функции ChooseFont
hwndOwner Идентификатор окна, которому будет принадлежать диалоговая панель. Если в поле Flags не указан флаг CF_SHOWHELP, в это поле можно записать значение NULL. Поле заполняется до вызова функции ChooseFont
hDC Идентификатор контекста отображения или информационного контекста для принтера. Если установлен флаг CF_PRINTERFONTS, в списке появятся шрифты, доступные в данном контексте
lpLogFont Указатель на структуру LOGFONT. Приложение может заполнить нужные поля в этой структуре перед вызовом функции ChooseFont. Если при этом будет установлен флаг CF_INITTOLOGFONTSTRUCT, выбранные значения будут использоваться в качестве начальных.
iPointSize Размер букв выбранного шрифта в десятых долях пункта. Содержимое этого поля устанавливается после возврата из функции ChooseFont
Flags Флаги инициализации диалоговой панели. Можно использовать следующие значения:CF_APPLY - разрешается использование кнопки "Apply";CF_ANSIONLY - в списке выбора появляются только шрифты в кодировке ANSI;CF_BOTH - в списке шрифтов появляются экранные и принтерные шрифты;CF_TTONLY - можно выбирать только масштабируемые шрифты True Type;CF_EFFECTS - если указан этот флаг, с помощью диалоговой панели можно определять цвет букв создавать подчеркнутые и перечеркнутые шрифты. В этом случае необходимо перед вызовом функции проинициализировать содержимое полей lfStrikeOut, lfUnderline, rgbColors;CF_ENABLEHOOK - разрешается использовать функцию фильтра адрес которой указан в поле lpfnHook;CF_ENABLETEMPLATE - разрешается использование шаблона диалоговой панели, определяемого содержимым полей hInstance и lpTemplateName;CF_ENABLETEMPLATEHANDLE - флаг указывает, что поле hInstance содержит идентификатор загруженного шаблона диалоговой панели. Содержимое поля lpTemplateName игнорируется;CF_FIXEDPITCHONLY - можно выбрать только шрифты с фиксированной шириной символов:CF_FORCEFONTEXIST - выдается сообщение об ошибке, если пользователь пытается выбрать несуществующий шрифт;CF_INITTOLOGFONTSTRUCT - для инициализации диалоговой панели используется содержимое структуры LOGFONT, адрес которой передается через поле lpLogFont;CF_LIMITSIZE - при выборе шрифта учитывается содержимое полей nSizeMin и nSizeMax;CF_NOFACESEL - отменяется выбор в списке "Font";CF_NOOEMFONTS - нельзя выбирать векторные шрифты, этот флаг аналогичен флагу CF_NOVECTORFONTS;CF_NOSIMULATIONS - запрещается эмуляция шрифтов;CF_NOSIZESEL - отменяется выбор размера шрифта;CF_NOSTYLESEL - отменяется выбор стиля шрифта;CF_NOVECTORFONTS - нельзя выбирать векторные шрифты, этот флаг аналогичен флагу CF_NOOEMFONTS;CF_PRINTERFONTS - в списке появляются только такие шрифты, которые поддерживаются принтером, контекст отображения для которого задан в поле hDC;CF_SCALABLEONLY - можно выбирать только масштабируемые и векторные шрифты;CF_SCREENFONTS - можно выбирать только экранные шрифты;CF_SHOWHELP - в диалоговой панели отображается кнопка "Help";CF_USESTYLE - строка lpszStyle содержит указатель на буфер, который содержит строку описания стиля. Эта строка используется для инициализации списка "Font Style" диалоговой панели "Font";CF_WYSIWYG - можно выбирать только такие шрифты, которые доступны и для отображения на экране, и для печати на принтере. Если установлен этот флаг, следует также установить флаги CF_BOTH и CF_SCALABLEONLY
rgbColors Цвет символов шрифта, который будет выбран в меню "Colors" диалоговой панели "Fonts" сразу после отображения диалоговой панели. Должен использоваться флаг CF_EFFECTS. Поле заполняется до вызова функции ChooseFont, после возврата из функции поле содержит значение выбранного цвета
lCustData Произвольные данные, передаваемые функции фильтра, определенной содержимым поля lpfnHook
lpfnHook Указатель на функцию фильтра, обрабатывающую сообщения, поступающие в диалоговую панель. Для работы с фильтром необходимо в поле Flags указать флаг CF_ENABLEHOOK
lpTemplateName Строка, закрытая двоичным нулем, которая содержит идентификатор шаблона диалоговой панели. Для использования этого поля необходимо указать флаг CF_ENABLETEMPLATE
hInstance Идентификатор модуля, который содержит шаблон диалоговой панели в качестве ресурса. Поле используется только в тех случаях, когда в поле Flags указаны значения CF_ENABLETEMPLATE или CF_ENABLETEMPLATEHANDLE. Поле заполняется до вызова функции ChooseFont
lpszStyle Указатель на буфер, содержащий строку, описывающую шрифт. Если указан флаг CF_USESTYLE, эта строка используется для инициализации списка "Font Style". Размер буфера должен быть не меньше LF_FACESIZE байт
nFontType Тип выбираемого шрифта. Можно использовать одно из следующих значений:SIMULATED_FONTTYPE - GDI может эмулировать этот шрифт;PRINTER_FONTTYPE - принтерный шрифт;SCREEN_FONTTYPE - экранный шрифт;BOLD_FONTTYPE - жирный шрифт, используется только для шрифтов True Type;ITALIC_FONTTYPE - наклонный шрифт, используется только для шрифтов True Type;REGULAR_FONTTYPE - не жирный и не наклонный шрифт, используется только для шрифтов True Type
nSizeMin Минимальный размер шрифта, который можно выбрать. Для использования этого поля необходимо установить флаг CF_LIMITSIZE
nSizeMax Максимальный размер шрифта, который можно выбрать. Для использования этого поля необходимо установить флаг CF_LIMITSIZE
Если пользователь выбрал шрифт, функция ChooseFont возвращает значение TRUE. Если пользователь отказался от выбора, нажав кнопку "Cancel" или клавишу <Esc>, возвращается значение FALSE.


Функция EnumFontFamilies


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

Приведем прототип функции EnumFontFamilies:

int EnumFontFamilies( HDC hdc, // идентификатор контекста отображения LPCSTR lpszFamily, // адрес имени семейства шрифта FONTENUMPROC fntenmprc, // адрес функции обратного вызова LPARAM lParam); // произвольные данные

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

Через параметр lpszFamily передается адрес строки, закрытой двоичным нулем, содержащей название шрифта, для которого требуется получить информацию. Если этот параметр указан как NULL, выбирается один произвольный шрифт для каждого семейства шрифтов.

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

Приложение может передать функции обратного вызова произвольные 32-разрядные данные через параметр lParam.

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

int CALLBACK _export EnumFontFamProc( NEWLOGFONT FAR* lpnlf, // адрес структуры NEWLOGFONT NEWTEXTMETRIC FAR* lpntm, // адрес структуры метрики // физического шрифта int FontType, // тип шрифта LPARAM lParam); // адрес произвольных данных, переданных // функции EnumFontFamilies через // параметр lParam

Когда функция EnumFontFamProc получает управление, через параметр lpnlf передается адрес структуры NEWLOGFONT , которая по непонятной причине не описана в файле windows.h. Эта структура аналогична структуре LOGFONT, но имеет в конце два дополнительных поля, определенных только для шрифтов True Type:

typedef struct tagNEWLOGFONT { int lfHeight; int lfWidth; int lfEscapement; int lfOrientation; int lfWeight; BYTE lfItalic; BYTE lfUnderline; BYTE lfStrikeOut; BYTE lfCharSet; BYTE lfOutPrecision;
BYTE lfFullName[2 * LF_FACESIZE];// только для True Type

BYTE lfStyle[LF_FACESIZE]; // только для True Type } NEWLOGFONT;

Поле lfFullName представляет собой массив, содержащий полное имя шрифта, которое состоит из названия шрифта и названия стиля.

В поле lfStyle находится название стиля шрифта.

Параметр lpntm функции EnumFontFamProc содержит адрес структуры NEWTEXTMETRIC , описывающей метрику шрифта:

typedef struct tagNEWTEXTMETRIC { int tmHeight; int tmAscent; int tmDescent; int tmInternalLeading; int tmExternalLeading; int tmAveCharWidth; int tmMaxCharWidth; int tmWeight; BYTE tmItalic; BYTE tmUnderlined; BYTE tmStruckOut; BYTE tmFirstChar; BYTE tmLastChar; BYTE tmDefaultChar; BYTE tmBreakChar; BYTE tmPitchAndFamily; BYTE tmCharSet; int tmOverhang; int tmDigitizedAspectX; int tmDigitizedAspectY;

// Дополнительные поля DWORD ntmFlags; UINT ntmSizeEM; UINT ntmCellHeight; UINT ntmAvgWidth; } NEWTEXTMETRIC; typedef NEWTEXTMETRIC* PNEWTEXTMETRIC; typedef NEWTEXTMETRIC NEAR* NPNEWTEXTMETRIC; typedef NEWTEXTMETRIC FAR* LPNEWTEXTMETRIC;

Структура NEWTEXTMETRIC аналогична структуре TEXTMETRIC, за исключением четырех дополнительных полей, добавленных в конце. Эти поля описывают физические атрибуты шрифта True Type.

Поле ntmFlags может содержать значения NTM_REGULAR, NTM_BOLD или NTM_ITALIC, соответственно, для нормального, жирного или наклонного шрифта True Type.

Поле ntmSizeEM содержит ширину буквы "М", в единицах, использованных при разработке шрифта.

В поле ntmCellHeight находится высота шрифта в единицах, использованных при разработке шрифта.

Поле ntmAvgWidth содержит ширину шрифта в единицах, использованных при разработке шрифта.

Параметр FontType функции EnumFontFamProc определяет тип шрифта и может содержать одно из следующих значений:

Значение Описание
DEVICE_FONTTYPE Шрифт устройства вывода
RASTER_FONTTYPE Растровый шрифт
TRUETYPE_FONTTYPE Шрифт True Type
Через последний параметр функции EnumFontFamProc передаются 32-разрядные данные, указанные в параметре lParam функции EnumFontFamilies.

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


Функция 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.



Функция PrintDlg


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

Рис. 6.1. Диалоговая панель "Print"

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

С помощью группы органов управления "Print Range" вы можете выбрать диапазон страниц, которые должны быть распечатаны. Можно распечатать все или отдельные страницы, выделенный фрагмент текста или страницы в указанном диапазоне номеров страниц (поля "From" и "To").

Можно задать качество печати (поле "Print Quality"), указать количество копий (поле "Copies"), выполнить печать в файл (поле "Print to File").

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

Если нажать на кнопку "Setup...", на экране появится диалоговая панель "Print Setup" (рис. 6.2).

Рис. 6.2. Диалоговая панель "Print Setup"

В группе органов управления "Printer" вы можете выбрать для печати либо принтер, принятый по умолчанию ("Default Printer"), либо выбрать другой принтер из списка "Specific Printer".

С помощью переключателей группы "Orientation" вы можете выбрать вертикальное ("Portrait") либо горизонтальное ("Landscape") расположение текста на листе бумаги.


Группа "Paper" содержит два списка, с помощью которых вы можете выбрать размер бумаги (список "Size") или устройство подачи бумаги ("Source").

Нажав в этой диалоговой панели кнопку "Options...", вы сможете выполнить настройку параметров принтера при помощи диалоговой панели "Options" (рис.6.3).



Рис. 6.3. Диалоговая панель "Options" для лазерного принтера HP LaserJet III

Внешний вид диалоговой панели "Options" зависит от драйвера принтера, так как эта панель формируется функцией DeviceMode или ExtDeviceMode, расположенными в соответствующем драйвере принтера. Для сравнения на рис. 6.4 представлен внешний вид диалоговой панели "Options" для матричного принтера Epson FX-850.



Рис. 6.4. Диалоговая панель "Options" для матричного принтера Epson FX-850

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

Приведем прототип функции PrintDlg, описанный в файле commdlg.h:

BOOL PrintDlg(PRINTDLG FAR* lppd);

При успешном завершении функция возвращает значение TRUE. В случае ошибки, отмены печати или отмены выбора принтера (если функция PrintDlg используется только для выбора принтера) функция возвращает значение FALSE.


HDC


Контекст устройства или информационный контекст.

Это поле заполняется после возвращения из функции PrintDlg, если в поле Flags указано одно из значений: PD_RETURNDC или PD_RETURNIC. В первом случае возвращается контекст принтера, который можно использовать для печати, во втором - информационный контекст, который можно использовать для получения разнообразной информации о принтере.



HDevMode


Идентификатор глобального блока памяти, содержащего структуру типа DEVMODE, которая используется для инициализации параметров принтера.

Если содержимое этого поля указать как NULL, после возвращения из функции PrintDlg поле будет содержать идентификатор глобального блока памяти, заказанного функцией. В этом блоке памяти будет расположена структура DEVMODE, заполненная выбранными параметрами принтера. Структура DEVMODE будет описана позже.



HDevNames


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

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



HInstance


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



HPrintTemplate


Идентификатор блока памяти, содержащего предварительно загруженный шаблон диалоговой панели "Print". Для использования этого поля необходимо указать флаг PD_ENABLEPRINTTEMPLATEHANDLE.



HSetupTemplate


Идентификатор блока памяти, содержащего предварительно загруженный шаблон диалоговой панели "Print Setup". Для использования этого поля необходимо указать флаг PD_ENABLESETUPTEMPLATEHANDLE.



HwndOwner


Идентификатор окна, создавшего диалоговую панель. Если в поле Flags не указано значение PD_SHOWHELP, в поле hwndOwner можно указать NULL.



Информационный контекст


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

Информационный контекст создается при помощи функции CreateIC , аналогичной по своим параметрам функции CreateDC:

HDC WINAPI CreateIC( LPCSTR lpszDriver, // имя драйвера LPCSTR lpszDevice, // имя устройства LPCSTR lpszOutput, // имя файла или порта вывода const void FAR* lpvInitData); // данные для инициализации

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



Инструменты для рисования


Итак, теперь у вас есть представление о том, какая "бумага" используется для рисования. Вы смогли убедиться, что ее свойства намного богаче свойств обычной писчей бумаги или даже дорогой бумаги, предназначенной для печати документов или крупных денежных купюр. Теперь посмотрим, какие "карандаши" может использовать приложение Windows для рисования. Можно предположить, что при такой бумаге и карандаши тоже будут не простые...

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

Расскажем кратко об основных особенностях и областях применения перечисленных выше инструментов.



Использование цветовых палитр


В большинстве случаев вам не потребуется использовать палитры Windows, так как далеко не все приложения работают с большим количеством цветов. Приложения для обычной презентационной графики (схемы, диаграммы и т. п.), обработки текстовых документов и другие аналогичные приложения выглядят вполне удовлетворительно при использовании 16 цветов, обеспечиваемых стандартным драйвером VGA. Более того, увеличение цветового разрешения, как правило, сказывается отрицательно на производительности Windows. И это понятно - чем больше используется цветов, тем больше объем данных, передаваемых из процессора в видеоконтроллер. Несмотря на то что акселераторы Windows значительно ускоряют работу, очень много пользователей имеют дешевые видеоконтроллеры, работающие в режиме низкого или, в крайнем случае, среднего цветового разрешения.

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

Оценивая отношение цветового разрешения к цене для разрешения 256 цветов, многие пользователи склоняются не к акселераторам с объемом видеопамяти 1-2 Мбайт (цена которых находится в диапазоне 100-400 долларов), а к обычным видеоадаптерам SVGA с объемом видеопамяти 512 Кбайт (цена порядка 40 долларов). Возможно, это неправильно, так как акселераторы и в самом деле заметно ускоряют работу Windows, однако едва ли вам понравится идея убеждать потенциальных покупателей вашего приложения обновить свой компьютер.

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

Вы можете спросить: будет ли ваше приложение, рассчитанное на использование цветовых палитр, работать с современными видеоадаптерами в режиме True Color, для которых механизм палитр не предусмотрен (так как в этом случае он не нужен)? Будет, так как GDI все равно сможет (и даже с большим успехом) удовлетворить цветовые запросы приложения.



Использование встроенной кисти


Для выбора одной из встроенной кисти вы можете воспользоваться макрокомандой GetStockBrush , определенной в файле windowsx.h:

#define GetStockBrush(i) ((HBRUSH)GetStockObject(i))

В качестве параметра для этой макрокоманды можно использовать следующие значения:

Значение Описание
BLACK_BRUSH Кисть черного цвета
WHITE_BRUSH Кисть белого цвета
GRAY_BRUSH Серая кисть
LTGRAY_BRUSH Светло-серая кисть
DKGRAY_BRUSH Темно-серая кисть
NULL_BRUSH Бесцветная кисть, которая ничего не закрашивает
HOLLOW_BRUSH Синоним для NULL_BRUSH

Как видно из только что приведенной таблицы, в Windows есть только монохромные встроенные кисти.

Макрокоманда GetStockBrush возвращает идентификатор встроенной кисти.

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

#define SelectBrush(hdc, hbr) \ ((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbr)))

Макрокоманда SelectBrush возвращает идентификатор старой кисти, выбранной в контекст отображения раньше.



Изображение bitmap


В контекст отображения можно выбрать изображение bitmap и затем отобразить его в окне или использовать в меню. Мы будем обсуждать изображения bitmap в отдельной главе этого тома. Сейчас отметим, что по умолчанию в контекст отображения не выбирается никакое изображение bitmap. Приложение должно выбрать его самостоятельно, используя функцию SelectObject . В программном интерфейсе GDI имеются и другие функции для работы с изображениями bitmap. Это функции CreateBitmap , CreateBitmapIndirect , CreateCompatibleBitmap .

Приложения Windows широко пользуются изображениями bitmap, так как они очень удобны для отображения небольших пиктограмм или больших и сложных многоцветных рисунков, полученных при помощи специальных графических редакторов или сканеров. Заметим, что в предыдущих томах "Библиотеки системного программиста" мы использовали изображения bitmap для кнопок и органа управления Toolbar, отложив подробное их изучение на потом.