Окт 13

Обработка сообщения WM_PAINT

Обработка сообщения WM_PAINT крайне важна для программирования под Windows. Это сообщение уведомляет программу, что часть или вся клиентская область окна недействительна (invalid) и ее следует перерисовать. Во второй главе тема обработки сообщения WM_PAINT будет рассмотрена более подробно, поэтому здесь излагается тот минимум, который необходим для понимания работы программы Hellol.
В каких ситуациях клиентская область окна становится недействительной? Очевидно, что при создании окна недействительна вся его клиентская область, поскольку в ней еще ничего не нарисовано. Это раз.
Если вы меняете размеры окна, клиентская область также объявляется системой недействительной, что обусловлено комбинацией стилей CS_HREDRAW | CS_VREDRAW в поле style структуры класса окна. Это два.
Когда вы минимизируете окно программы Hellol, сворачивая его на панель задач, а затем снова разворачиваете до начального размера, то Windows объявляет клиентскую область окна недействительной. Это три.
Если вы перемещаете окна так, что они перекрываются, а затем закрытая часть окна вновь открывается, то Windows помечает требующую восстановления клиентскую область как недействительную. Это четыре.
Можно было бы продолжить, но оставим подробности для второй главы.
Во всех перечисленных случаях, кроме первого, операционная система автоматически помечает клиентскую область окна как недействительную, что влечет за собой посылку сообщения WM_PAINT. В первом случае, когда окно только что было создано, аналогичный эффект достигается вызовом функции ShowWindow. В процессе ее выполнения генерируются сообщения WM_SIZE и WM_M0VE, а обрабатывая WM_SIZE, система автоматически генерирует сообщение WM_PAINT.
Завершив этот маленький теоретический экскурс, вернемся к анализу нашего кода.
Обработку сообщения WM_PAINT рекомендуется всегда начинать с вызова функции Begin Paint:
hDC - BeginPainUhWnd, &ps);
Первый параметр функции содержит дескриптор окна, полученный через аргумент оконной процедуры, а второй — адрес структуры ps типа PAINTSTRUCT. Поля этой структуры, заполняемые в результате выполнения функции BeginPaint, в дальнейшем используются операционной системой1. Для нас сейчас более важно возвращаемое функцией значение — это дескриптор так называемого контекста устройства.
Контекст устройства (device context) описывает физическое устройство вывода информации, например дисплей или принтер. Этот важнейший объект графической подсистемы Windows рассматривается подробно во второй главе. Сейчас достаточно понимания того, что контекст устройства — это некоторая внутренняя структура данных, сохраняющая часто используемые графические атрибуты, такие как цвет фона, перо, кисть, шрифт и им подобные параметры. Эти атрибуты используются при вызове всех рисующих функций, получающих дескриптор hDC в качестве параметра.
Прежде чем перейти к следующей строке программного текста, отметим два побочных эффекта выполнения функции BeginPaint.
Во-первых, обрабатывая вызов BeginPaint, система Windows обновляет фон клиентской области, если обновляемый регион помечен для стирания1. По умолчанию для этого используется кисть, заданная в поле hbrBackground структуры WNDCLASSEX.
Во-вторых, вызов функции BeginPaint делает всю клиентскую область действительной (valid), то есть не требующей перерисовки. Это предотвращает повторную генерацию системой сообщения WM_PAINT до тех пор, пока вновь не произойдет одно из событий, требующих перерисовки окна.
После вызова BeginPaint в рассматриваемой программе следует вызов функции GetClientRect, предназначенной для получения размеров клиентской области окна:
GetClientRect(hWnd. Srect);
Результат работы функции помещается в переменную rect типа RECT. Структура RECT, описывающая прямоугольник (rectangle), определена в заголовочных файлах Windows следующим образом:
typedef struct tagRECT {
LONG left;
LONG top;
LONG right;
LONG bottom; } RECT;
Поля этой структуры задают координаты левого верхнего угла (left, top) и правого нижнего угла (right, bottom) прямоугольника.
После выполнения функции GetClientRect поля left и top всегда получают нулевое значение, а поля right и bottom содержат ширину и высоту клиентской области в пикселах. Информация о размерах клиентской области, сохраненная в переменной rect, используется далее в «рисующей» функции DrawText.
В нашей программе все «рисование» сводится к выводу текста «Hello, World!» при помощи функции DrawText, имеющей следующий прототип:
BOOL DrawText(
HDC hdc. // дескриптор контекста устройства
LPCTSTR IpString. // указатель на символьную строку
int nCount, // длина текста
LPRECT lpRect, // указатель на ограничивающий прямоугольник
UINT uFormat // флаги форматирования текста );
Функция2 выводит текст из строки IpString в прямоугольную область, заданную структурой типа RECT, используя метод форматирования, заданный параметром uFormat Количество символов в выводимой строке задается параметром nCount. Если установить значение nCount в -1, то система сама определит длину строки IpString по завершающему нулевому символу. Но в этом случае программист должен позаботиться о том, чтобы строка действительно завершалась нулевым байтом.
На месте последнего параметра функции задан набор флагов DT_SINGLELINE | DT_CENTER | DT_VCENTER, значения которых определяются в заголовочных файлах Windows. Флаги показывают, что текст будет выводиться в одну строку, по центру относительно горизонтали и вертикали внутри прямоугольной области, заданной четвертым параметром. Благодаря этому текст «Hello, World!» выводится в центре клиентской области.
Когда клиентская область становится недействительной (например, при изменении размеров окна), WndProc получает новое сообщение WM_PAINT. Обрабатывая его, программа вновь вызывает функцию GetClientRect и поэтому рисует текст опять в центре окна.
После окончания работы с графическими функциями в блоке обработки сообщения WM_PAINT необходимо освободить полученный контекст устройства с помощью функции EndPaint.
Следует отметить, что при выводе текста используются текущие установки для шрифта, цвета фона и цвета текста. О том, как управлять этими атрибутами, будет рассказано во второй главе. Для тех, кто хочет экспериментировать с цветами текста и фона немедленно, ниже приводится краткая справка.