Графический интерфейс GDI в Microsoft Windows
Введение
Предыдущие три тома «Библиотеки системного программиста» представляли собой краткое (!) введение в программирование для операционной системы Microsoft Windows. В них мы рассказали вам только о некоторых возможностях, не углубляясь в тонкости графического интерфейса и других подсистем. Мы также отложили рассказ о таких важных понятиях, как многооконный интерфейс MDI, протокол обмена данными между приложениями DDE, системе привязки и вставки объектов OLE.
В книге, которую вы сейчас держите в руках, мы расскажем о графическом интерфейсе GDI (Graphic Device Interface — интерфейс графических устройств), посредством которого графическая операционная система Windows выводит графику и текст на экран, принтер, плоттер и другие аналогичные устройства. В предыдущих томах мы уже упоминали о GDI, однако были рассмотрены только основные моменты, без понимания которых невозможно сделать ни одно приложение (разве что такое, которое не создает окон и ничего не выводит на экран или принтер).
Интерфейс GDI избавляет приложения Windows от необходимости учитывать многие (но не все) аппаратные особенности графических устройств вывода. Например, адресация видеопамяти выполняется по-разному в видеоадаптерах CGA, EGA, VGA, SVGA и, к тому же, структура видеопамяти сильно зависит от используемого режима (подробности вы можете найти третьем томе «Библиотеки системного программиста», который называется «Программирование видеоадаптеров CGA, EGA и VGA»). Однако приложения не работают непосредственно с видеопамятью. Для того чтобы нарисовать линию или написать строку текста, приложения вызывают ту или иную функцию интерфейса GDI, реализованного в виде DLL-библиотеки. Функции GDI также не работают с аппаратурой. Для выполнения нужной графической операции GDI вызывает драйвер устройства вывода, который «знает» о всех особенностях аппаратуры.
Таким образом, с помощью GDI приложения могут организовать вывод текста и графических изображений на некоторое логическое устройство вывода. Функции GDI и драйверы обеспечивают независимость приложений от аппаратуры, поэтому правильно созданное приложение Windows будет корректно работать с любыми видеоадаптерами и принтерами, как существующими на момент разработки приложения, так и с теми, которые появятся в будущем. В этом приложения Windows имеют большое преимущество над программами MS-DOS, вынужденными для повышения производительности работать непосредственно с регистрами видеоконтроллера и видеопамятью.
В первой главе вы познакомитесь с основными понятиями GDI, такими, как контекст отображения и его атрибуты, узнаете об инструментах, которые приложение Windows может использовать для рисования.
Вторая глава посвящена контексту отображения. Вы узнаете о типах контекста, научитесь получать и освобождать контекст отображения и контекст устройства. Мы расскажем вам об использовании режимов отображения, позволяющих работать с различными логическими системами координат. Отдельные разделы этой главы посвящены рисованию геометрических фигур и использованию областей.
В третьей главе мы расскажем о цвете и цветовых палитрах. Вы познакомитесь со статическими и системными цветами, научитесь создавать логическую палитру цветов и следить за изменениями системной палитры цветов. Все это позволит вам рисовать многоцветные изображения. Мы также расскажем об особенностях работы в режимах с высоким цветовым разрешением, таких как True Color.
Четвертая глава — об использовании битовых изображений. Вы узнаете о существовании различных типов битовых изображений и форматов bmp-файлов, содержащих изображения, научитесь рисовать битовые изображения, загруженные из bmp-файлов, а также создавать и использовать логическую палитру на базе таблицы цветов, расположенной в bmp-файле.
Пятая глава посвящена использованию шрифтов, в том числе масштабируемых шрифтов True Type. Будет рассмотрен механизм отображения шрифтов, который используется в процессе выделения шрифтов по запросу приложения. Мы расскажем о том, как выбрать нужный шрифт из числа установленных в системе, как получить различную информацию о шрифте, выбранном в контекст отображения. Несмотря на то что мы не привели полного описания функций GDI, предназначенных для работы с шрифтами True Type (оно занимает слишком много места), пользуясь нашей книгой вы сможете выполнять все основные операции, связанные с использованием шрифтов True Type. Если перед вами стоит задача разработки такого приложения, как редактор шрифтов True Type, вы сможете получить недостающую информацию из документации, которая поставляется вместе с Microsoft SDK for Windows 3.1.
В шестой главе рассмотрены средства, предназначенные для работы с принтером. Теперь ваши приложения смогут печатать текст и графику на любом принтере, установленном в системе. Мы научим вас пользоваться стандартными диалоговыми панелями, предназначенными для печати, выбора принтера и установки параметров принтера, опишем функции GDI, предназначенные для печати.
Мы привели исходные тексты приложений, демонстрирующих использование описанных средств GDI. Вы можете купить дискету, содержащую исходные тексты всех этих приложений.
Для трансляции исходных текстов приложений, приведенных в книге, мы пользовались системой разработки Borland Turbo C++ for Windows версии 3.1. Вы можете также использовать Borland C++ версий 3.1 или 4.0.
Чтобы вы смогли изучить приемы работы с палитрой и использовать режимы с высоким цветовым разрешением, в вашем компьютере должен быть установлен подходящий видеоадаптер и видеомонитор, способный работать в режимах SVGA. Обычный адаптер VGA в Windows предоставляет возможность работы всего лишь с 16 цветами, что недостаточно для многих графических приложений. Механизм цветовых палитр операционной системы Windows используется только в том случае, если в компьютере есть видеоадаптер SVGA, способный отображать 256 цветов. Лучше всего приобрести недорогой видеоадаптер с ускорителем для Windows, который может работать в режиме True Color (примерно 16 млн. цветов). Для отладки приложений, приведенных в этой книге, авторы использовали следующие видеоадаптеры: AVGA3 с видеопроцессором фирмы Cirrus Logic и объемом видеопамяти 1 Мбайт (акселератор для шины ISA стоимостью примерно 100 долларов), Orchid Fahrenheit VA-VLB (акселератор для шины VL-BUS), OAK VGA (адаптер SVGA с объемом видеопамяти 1 Мбайт без ускорителя).
Авторы выражают благодарность сотрудникам АО «Диалог-МИФИ» Елене Виноградовой, Олегу Александровичу Голубеву, Наталье Дмитриевой, Оксане Кузьминовой, корректору Виктору Кустову. Появление этой книги стало возможным только благодаря напряженному труду всех этих людей. Мы также благодарим за помощь в работе над книгой Максима Синева и Сергея Ноженко.
Работа MFC с GDI (GDI+)
Цель работы:
- Ознакомиться с функциями рисования примитивов
- Использовать перья и кисти для рисования различных частей графических примитивов
- Устанавливать различные режимы отображения контекста устройства
- Динамически загружать и отображать растровые рисунки разными способами и в разных форматах
Интерфейс графических устройств
Интерфейс графических устройств Windows ( GDI — Graphic Device Interface ) представляет собой виртуальное графическое устройство для всех приложений независимо от конкретных аппаратных средств, из которых состоит компьютер. GDI является неотъемлемой частью ядра операционной системы, контролирующей и обеспечивающей все операции графического вывода приложений Windows .
Корпорация Microsoft создала GDI , чтобы отделить графические операции от фактически используемого оборудования. Для программиста предоставлены графические функции высокого уровня абстракции, которые обеспечивают одинаковые результаты выполнения независимо от используемого оборудования. От разработчиков аппаратных средств требуется обеспечить поставку и драйверов (программ управления оборудованием на низком уровне) для естественного подключения их к функциям GDI .
Пользовательская сторона GDI (пользователь GDI — это разработчик приложения) реализована с помощью контекста устройства. Контекст графического устройства — это конкретная настройка GDI на выполнение графических операций. Управление контекстом устройства обеспечивается MFC -классом CDC . Объект, созданный с помощью этого класса, содержит все необходимые настройки GDI , установленные по умолчанию или пользователем (разработчиком приложения). Фактически экземпляр класса CDC или производных от него классов и представляет собой контекст устройства, олицетворяя собой все настройки GDI .
Контекст устройства способен обеспечить вывод изображений на любое внешнее устройство, будь то экран, принтер, графопостроитель и т.д. При этом используются одни и те же функции GDI . Для отображения изображения на экране приложению необходимо иметь контекст устройства экрана, для отображения на принтере — контекст другого устройства — принтера.
Контексты экрана и принтера называются физическими контекстами или контекстами вывода. Существуют еще два контекста устройства: растр и метафайл. Растр является тем же контекстом устройства, содержащим набор пикселов и по своей структуре готовый для подключению к физическому контексту, но пока хранящийся в памяти. Метафайл является набором готовых инструкций, способных создать графическое изображение перед подключением к физическому контексту.
Контекстов устройства, как экземпляров класса CDC , одновременно может быть создано в приложении несколько и все они будут храниться в памяти готовыми для подключения, но только один из них в текущий момент времени может быть связан с конкретным физическим устройством вывода информации. т.е. только один может служить физическим контекстом ( контекстом вывода ). Существуют наследники класса CDC , создающие контексты в частных случаях, например, CPaintDC, CClientDC . Поскольку CDC является базовым классом для всех других классов контекста устройства, все его методы доступны независимо от того, с каким классом контекста устройства мы работаем в данный момент.
Объекты контекста устройства, а равным образом и все различные объекты рисунка, классифицируются в Windows как ресурсы. Операционная система может иметь ограниченное количество таких ресурсов и они могут исчерпаться, если приложение занимает их и вовремя не освобождает. Эта потеря известна как утечка ресурсов и во многом подобна утечке памяти, поскольку тоже в конечном итоге приводит к блокировке системы.
Чтобы избежать утечки подобных ресурсов, удобнее создавать их как локальные на стеке в пределах тех функций, где они будут использоваться. Соответственно при выходе из такой функции ресурс автоматически освобождается. Единственное реальное исключение, — когда объект контекста устройства создается самой Windows и передается в функцию обработки события в качестве параметра pDC. Например
Некоторые свойства (атрибуты) контекста устройства представляют собой простые типы данных, встроенные прямо в контекст устройства. Но большинство графических атрибутов контекста устройства представляют собой сложные данные типа структур или даже классов со своими функциями членами. Экземпляры этих классов называются графическими атрибутами контекста устройства. Экземпляры этих классов нужно создавать, настраивать и подключать к контексту устройства, чтобы они должным образом влияли на графический вывод.
Поддержка цветов в GDI
Базовым типом данных Windows для хранения цветов является структура COLORREF . Проще всего задать цвет при помощи макрокоманды RGB , которой передаются три числовых значения от 0 до 255. Например:
Такой способ задания цвета в GDI называется логическим цветом. Но это только наше пожелание, а реальное отображение цвета определяется способностью аппаратного устройства. Монитор с высокой разрешающей способностью, расчитанный на отображение 24-битной или 32-битной глубины цвета не будет иметь никаких расхождений между логическим и физическим цветом. Для более слабых мониторов GDI будет сам осреднять цвета, подбирая наибольшее сходство между логическим (запрашиваемым) и физическим (реально отображаемым) цветом. Аналогичный процесс происходит и для принтеров.
Таким образом, если, например, красный цвет запрошен у физического устройства, способного его отобразить, то все нормально — мы получим то, что требовалось. Но если физическое устройство не способно отобразить запрошенный цвет, то оно применит самый близкий (с точки зрения GDI ). Для черно-белых принтеров GDI стремиться подобрать наиболее близкие цвета через оттенки серого, что иногда никуда не годится. Чтобы решить эту проблему, можно просто не запрашивать недоступные цвета. Чтобы выяснить, сколько цветов поддерживает конкретное физическое устройство, нужно обратиться к функции контекста этого устройства
Для цветных мониторов система предоставляет стандартную палитру из 20 цветов, на основании которой формируются все другие цвета.
Стандартная цветовая палитра GDI Windows | ||||||
---|---|---|---|---|---|---|
const COLORREF | g_crBlack | = RGB( | 0, | 0, | 0 | ) |
const COLORREF | g_crYellow | = RGB( | 255, | 255, | 0 | ) |
const COLORREF | g_crDkYellow | = RGB( | 128, | 12 | 0 | ) |
const COLORREF | g_crRed | = RGB( | 255, | 0, | 0 | ) |
const COLORREF | g_crDkRed | = RGB( | 128, | 0, | 0 | ) |
const COLORREF | g_crMagenta | = RGB( | 255, | 0, | 255 | ) |
const COLORREF | g_crDkMagenta | = RGB( | 128, | 0, | 128 | ) |
const COLORREF | g_crBlue | = RGB( | 0, | 0, | 255 | ) |
const COLORREF | g_crDkBlue | = RGB( | 0, | 0, | 128 | ) |
const COLORREF | g_crCyan | = RGB( | 0 | 255, | 255 | ) |
const COLORREF | g_crDkCyan | = RGB( | 0, | 128, | 128 | ) |
const COLORREF | g_crGreen | = RGB( | 0, | 255, | 0 | ) |
const COLORREF | g_crDkGreen | = RGB( | 0, | 128, | 0 | ) |
const COLORREF | g_crGray | = RGB( | 192, | 192, | 192 | ) |
const COLORREF | g_crDkGray | = RGB( | 128, | 128, | 128 | ) |
const COLORREF | g_crWhite | = RGB( | 255, | 255, | 255 | ) |
const COLORREF | g_crLtYellow | = RGB( | 255, | 251, | 240 | ) |
const COLORREF | g_crLtGreen | = RGB( | 192, | 220, | 192 | ) |
const COLORREF | g_crLtBlue | = RGB( | 166, | 202, | 240 | ) |
const COLORREF | g_crMedGray | = RGB( | 160, | 160, | 164 | ) |
Класс контекста устройства CDC имеет множество методов, но существуют три основных направления применения этих методов для управления функциями GDI :
Для каждого из них в GDI существуют свои функции управления, потому что на уровне драйверов устройств каждый из этих наборов операций имеет свою реализацию и выполняется по разному.