Опубликован: 15.11.2010 | Уровень: для всех | Доступ: платный
Лекция 10:

Общие сведения о контексте GDI

< Лекция 9 || Лекция 10: 123 || Лекция 11 >
Аннотация: На лекции описываются типы контекста отображения, правила их использования и функции для работы с разными типами контекстов. Описывается, почему надо обязательно закрывать контекст после его использования в операциях ввода-вывода.

10.1. Определение контекста отображения и устройства

Интерфейс графических устройств операционной системы Microsoft Windows (в дальнейшем - просто GDI) предназначено для взаимодействия приложений Windows с графическими устройствами ЭВМ. Использование такого "промежуточного уровня" между приложением Windows и устройством позволяет решить следующие проблемы:

  1. Средствами GDI можно вывести любой текст, изображение, форматирование на любое устройство ЭВМ, которое при подключении к операционной системе Windows имеет для неё собственный драйвер. Следовательно, единообразно можно вывести информацию на любое устройство: принтер, монитор, графопостроитель, в локальную или глобальную сеть, не занимаясь "прямым программированием устройств" (как это Вам пришлось осуществлять бы в MS-DOS);
  2. Средствами GDI осуществляется вывод не на физическое, а на "логическое" устройство. Это значит, что Вы, например, можете задать вывод картинки с 16 млн. цветов на монитор, поддерживающий только 256 цветов. Вывод изображения на "логический монитор" средствами GDI будет производиться единообразно, будут задействованы все 16 млн. цветов. Однако драйверы видеокарты и монитора учтут свои ограничения на имеющийся цветовой диапазон, и "автоматически" преобразуют картинку с 16 млн. цветами в картинку с 256 цветами. Драйвер принтера вообще преобразует эту картинку в двухцветное изображение, напечатав полутона в виде растра ("мозаики");
  3. Имея параметры физических устройств, подключённых ЭВМ, "ниже среднего уровня", Вы, тем не менее, можете создавать программы для любых "продвинутых устройств" ЭВМ, отсутствующих на Вашем компьютере. Более того, Вы можете осуществлять программирование устройств, ещё не созданных для данных ЭВМ - необходимо только, чтобы эти устройства были, во-первых, совместимые с ЭВМ на аппаратном уровне, а во-вторых, разработка их драйверов должна укладываться в стандарты, по которым создаются драйверы для указанного семейства устройств и стандартами Microsoft в написании драйверов к операционной системе Windows;
  4. Такая ситуация, когда приложение запрашивает у Windows одно, а получает другое, возникает не только при работе с цветом. Приложение может запросить для вывода шрифт, описав его характеристики, а GDI подберёт к выводу наиболее подходящий (с его точки зрения) шрифт, соответствующий описанию, и предоставит его приложению для вывода. Вначале такой подход обескураживает, но затем Вы начинаете понимать, что такой способ является единственным способом заставить работать программу Windows на любом оборудовании, любой аппаратной части. В самом деле, шрифтом, которым выводятся данные на экран, часто нельзя выводить данные на принтер - его может не быть в списке поддерживаемых шрифтов для данной модели принтера. И что же, из-за этого не выводить данные на принтер?…

Из чего состоит интерфейс GDI с точки зрения приложения?

Прежде всего, это контекст отображения и инструменты для рисования. Контекст является как бы листом бумаги, на котором приложения рисует графику и текст. Инструменты рисования - это перья, кисти (а также шрифты, курсоры, иконки, и даже целые графические изображения), с помощью которых создаётся изображение на устройстве. Если же говорить более точно, то контекст - это структура данных, описывающая устройство отображения. В этой структуре хранятся различные характеристики устройства и набор инструментов рисования, выбранные по-умолчанию. Приложение может выбирать в контексте отображения различные инструменты. Но собственно в функциях рисования изображений и вывода текста эти инструменты не указываются - они "наследуются" из контекста. Приложение сможет создать контекст отображения не только для экрана монитора или окна, но и для любого другого графического устройства вывода, например, принтера и графопостроителя. Можно создать контекст изображения для метафайла. Метафайл - это обычный файл или файл в памяти, в котором хранится последовательность команд интерфейса GDI. Приложение может осуществить вывод графической информации в метафайл, а затем вывести содержимое метафайла на любое устройство вывода.

Изучение GDI мы начнём с подробного описания контекста изображения и его атрибутов. Собственно схема взаимодействия контекста и драйверов устройства показана на рисунке 10.1.

Ввод-вывод данных через контекст устройства

Рис. 10.1. Ввод-вывод данных через контекст устройства

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

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

10.2. Правила работы с контекстом

10.2.1. Работа с контекстом отображения

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

  • получение или создание контекста отображения;
  • установка необходимых атрибутов в контексте отображения;
  • выполнение операций рисования;
  • освобождение либо удаление контекста отображения.

Последнее действие (освобождение либо удаление контекста отображения) должно быть обязательно выполнено. Самый простой способ полностью нарушить работоспособность Windows - забыть освободить полученный контекст отображения или забыть удалить созданный контекст отображения или устройства.

Так как контекст отображения - "самый критичный" ресурс Microsoft Windows, его необходимо освобождать сразу, как только в нём отпадает необходимость. Операционная система Microsoft Windows выполняет кэширование обычного контекста отображения, причём кэшируется только пять контекстов (информация для Microsoft Windows 3.11). Если операционная система не может удовлетворить запрос какого-либо приложения на выделение контекста отображения, вся операционная система окажется в критическом состоянии, из которого есть только один выход - перезагрузка Windows.

10.2.2. Типы контекстов отображения

Можно выделить следующие типы контекста отображения:

  • общий контекст отображения (common display context);
  • контекст отображения класса окна (class display context);
  • личный контекст отображения (private display context);
  • родительский контекст отображения (parent display context);
  • контекст отображения для окна (window display context);
  • контекст физического устройства (device context);
  • информационный контекст (information context);
  • контекст для памяти (memory device context);
  • контекст для метафайла (metafile context);

Каждый из перечисленных выше контекстов имеет свои особенности и своё назначение.

10.2.3. Общий контекст отображения

Этот контекст используется чаще всего, поэтому для ускорения доступа к нему Windows использует кэширование. Для получения общего контекста отображения приложение должно вызвать функцию BeginPaint (при обработке сообщения WM_PAINT ) или GetDC (при обработке других сообщений). При этом перед регистрацией класса окна в структуре WNDCLASS не должны использоваться значения CS_OWNDC, CS_PARENTDC или CS_CLASSDC. Например:

wc.style = 0;
Листинг 10.1.

Функция BeginPaint возвращает контекст отображения для окна hwnd:

HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT FAR *lpps);
Листинг 10.2.

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

Назначение полей структуры PAINTSTRUCT смотри в приложении № I к данной лекции (п. 10.4).

Контекст отображения, полученный с помощью функции BeginPaint, необходимо освободить перед завершением обработки сообщения WM_PAINT, вызвав функцию EndPaint с теми же параметрами:

void WINAPI EndPaint( HWND hwnd, PAINTSTRUCT FAR *lpps);
Листинг 10.3.

Примечание: функции BeginPaint и EndPaint можно использовать только внутри обработчика сообщения WM_PAINT. Если приложению Microsoft Windows требуется рисовать при обработке других сообщений, оно должно получить контекст отображения с помощью функции GetDC и освободить функцией ReleaseDC ;

Функция GetDC возвращает контекст отображения для окна с идентификатором hwnd:

HDC WINAPI GetDC( HWND hwnd );
Листинг 10.4.

Функция ReleaseDC освобождает контекст изображения hdc, полученный для окна hwnd:

int WINAPI ReleaseDC( HWND hwnd, HDC hdc );
Листинг 10.5.

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

< Лекция 9 || Лекция 10: 123 || Лекция 11 >