Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
A05_API.doc
Скачиваний:
5
Добавлен:
12.11.2019
Размер:
1.3 Mб
Скачать

Контрольные вопросы

5.4. Программирование графики

5.4.1. Основные средства. Графический интерфейс устройства (graphic device interface, GDI) – это составная часть Windows API, обеспечивающая графический вывод на устройства отображения информации, такие, как дисплей или принтер. Windows – приложение не имеет непосредственного доступа к аппаратным устройствам. Вместо этого оно обращается к функциям GDI, а GDI транслирует эти обращения к программным драйверам физических устройств, обеспечивая аппаратную независимость приложений (рис. 5.4). Код библиотеки GDI находится в файле gdi32.dll, т.е. библиотека является динамически загружаемой. Драйверы стандартных устройст поставляются как часть Windows, а драйверы специализированных устройств создаются производителями оборудования.

Соотношение между приложениями, GDI и драйверами устройств

Рис. 5.4

5.4.2. Контекст устройства. Взаимодействие приложения с GDI осуществляется при непременном участии еще одного посредника – так называемого контекста устройства.

Контекст устройства (device context) – это внутренняя структура данных, которая определяет набор графических объектов и ассоциированных с ними атрибутов, а также графических режимов, влияющих на вывод.

В следующем списке приведены основные графические объекты:

  • перо (pen) ддя рисования линий;

  • кисть (brush) для заполнения фона или заливки фигур;

  • растровое изображение (bitmap) для отображения в указанной области окна;

  • палитра (palette) для определения набора доступных цветов;

  • шрифт (font) для вывода текста;

  • регион (region) для отсечения области вывода.

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

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

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

5.4.3. Типы контекстов устройства. Windows поддерживает следующие типы контекстов устройства:

      • контекст дисплея;

      • контекст принтера;

      • контекст в памяти (совместимый контекст);

      • метафайловый контекст;

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

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

5.4.4. Регионы Windows. Отсечение. Контекст устройства. Для повышения эффективности работы Windows оперирует с несколькими типами регионов. Идея заключается в том, чтобы рисовать именно в той части окна, которая требует обновления, а не перерисовывать все окно. Такие регионы позволяют отсекать вывод той части графической информации, которая не может быть отображена в данный момент. Вообще полное изучение всей иерархии регионов и их взаимодействия является непростой задачей, требующей пространного изложения. В то же время, приведенное ниже упрощенное описание достаточно для понимания работы большинстыв функций Windows API.

Обновляемый регион (update region), или как его тоже иногда называют, недействительный регион (invalid region) – это часть окна, которая требует обновления после возникновения тех или иных событий.

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

Регион отсечения (clipping region) ограничивает область, внутри которой система разрешает отображение графической информации. Когда приложение получает контекст устройства при помощи функции BeginPaint, система устанавливает регион отсечения путем пересечения видимого региона и обновляемого региона. Приложение может ужесточить регион отсечения и ввести дополнительные ограничения при помощи вызова функций SetWindowRgn, SelectClipPath или SelectClipRgn.

Если при создании окна функцией CreateWindow был использован стиль WS_CLIPCHILDREN или WS_CLIPSIBLINGS, то это вносит дополнительные правила в определение видимого региона, исключая из него любое дочернее или любые «сестринские» окна. Благодаря этому рисование не затрагивает отбражаемые области таких окон.

5.4.5. Контекст дисплея. Контекст устройства Контекст дисплея создавать не нужно – об этом уже позаботилась операционная система. Нужно лишь получить его дескриптор. Windows предоставляет для этого два метода. Для ая требует обновления после возникновения тех или иных событий.

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

HDC BeginPaint (

HWND hWnd, // дескриптор окна

LPPAINTSTRUCT lPaint // указатель на структуру типа PAINTSTRUCT

);

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

Кроме этого функция заполняет поля структуры PAINTSTRUCT, имеющей следующее определение:

typedef struct tagPAINTSTRUCT

{

HDC hdc; // контекст устройства

BOOL fErase;// признак стирания фона клиентской области

RECT rcPaint; // границы недействительного прямоугольника

BOOL fRestore;

BOOL fIncUpdate;

BYTE rgbReserved[32];

} PAINTSTRUCT;

Последние три поля используются операционной системой.

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

Поле fErase определяет, будет ли Windows обновлять фон недействительного региона. Чаще всего fErase имеет значение TRUE, что означает стирание (обновление) фона.. Когда обновляемый регион формируется вызовом функции InvalidateRect или InvalidateRgn, один из параметров этих функций разрешает или подавляет стирание фона.

Если задано стирание фона, то функция BeginPaint посылает оконной процедуре сообщение WM_ERASEBKGND. Приложение может обработать это сообщение, чтобы отобразить однородный или растровый фон. Однако обычно сообщение обрабатывается по умолчанию функцией DefWindowProc, которая обновляет фон с использованием кисти, определенной в поле hbrBackground класса окна.

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

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

Типовой процесс обработки сообщения WM_PAINT выглядит следующим образом:

case WM_PAINT:

hDC = BeginPaint (hWnd, &ps);

[использование функций GDI]

EndPaint (hWnd, &ps);

return 0;

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

Второй метод получения дескриптора контекста устройства. Иногда рисование должно происходить не в блоке обработки сообщения WM_PAINT, а при обработке других сообщений. Или, быть может, дескриптор контекста устройства нужен не для рисующих, а для иных функций (например, в качестве аргумента функции GetTextMetrics), вызываемых вне блока обработки сообщения WM_PAINT. В таких ситуациях контекст устройства получают либо вызовом функции GetDC:

hdc = GetDC (hWnd);

либо вызовом функции GetWindowDC:

hdc = GetWindowDC (hWnd);

Первая функция возвращает дескриптор контекста дисплея для клиентской области окна hWnd, а вторая – для всего окна. Если в качестве аргумента hWnd передать значение NULL, то обе функции вернут дескриптор устройства для всего экрана.

По окончании работы с функциями GDI необходимо освободить контекст устройства с помощью функции ReleaseDC, например:

hDC = GetDC (hWnd);

[использование функций GDI]

ReleaseDC (hWnd, hDC);

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

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

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

  • изменились размеры или местоположение окна;

  • клиентская область была частично или полностью закрыта другим окном или выпадающим меню, а теперь закрывающий объект исчез;

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

Кроме того, приложение может само инициировать посылку сообщения WM_PAINT посредством вызова одной из функций, InvalidateRect, InvalidateRgn или UpdateWindow.

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

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

5.4.7. Использование функций InvalidateRect и InvalidateRgn. Если в каком-то месте алгоритма необходимо сгенерировать сообщение WM_PAINT для перерисовки некоторой части окна, то приложение может воспользоваться функциями InvalidateRect и InvalidateRgn.

Функция InvalidateRect имеет следующий прототип:

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]