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




 

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

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

Замечание. В силу различных технических причин при перемещении, а иногда и при изменении размеров окон их содержимое сохраняется и перерисовывается систе­мой. Однако это не касается тех случаев, когда окно минимизируется или перекрывается другим окном, а затем восстанавливается в исходное состояние.

Прежде чем объяснять, как обрабатывается WM_PAINT, будет полезно расска­зать, почему Windows не перерисовывает окно автоматически. В большинстве случаев перерисовать окно проще программе, нежели Windows, поскольку именно програм­ма, а не Windows, должна «знать» о содержимом окна и способах его перерисовки. И хотя достоинства этого подхода являются спорными, в данном случае нужно просто принять его, поскольку не похоже, что он будет меняться.

Первым шагом в обработке сообщения WM_PAINT будет добавление соответ­ствующего case в оператор switch функции окна, как показано ниже:

 

// Обработка запроса на перерисовку окна

case WM_PAINT:

hdc=BeginPaint(hwnd,&paintstruct); // Получить DC

TextOut(hdc,1,1,str,strlen(str)); // Вывести буфер

EndPaint(hwnd, &paintstruct); // Освободить DC

break;

 

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

HDC BeginPaint(HWND hwnd, LPPAINTSTRICT lpPS);

 

Второй параметр является указателем на структуру PAINTSTRUCT, которая определяется следующим образом:

 

typedef struct tagPAINTSTRUCT

{

HDC hdc; // Дескриптор DC

BOOL fErase; // Истина, если перерисовывается окно

RECT rcPaint; // Координаты области перерисовки

BOOL fRestore; // Зарезервировано

BOOL flncUpdate; // Зарезервировано

BYTE rgbReserved[32]; // Зарезервировано

} PAINTSTRUCT;

 

Тип RECT – это структура, описывающая прямоугольную область:

 

typedef struct tagRECT

{

LONG left, top; // Верхний левый угол

LONG right, bottom; // Правый нижний угол

} RECT;

 

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

 

Пример 3-2. Ниже приводится полный текст программы обработки сообщения WM_PAINT:

 

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

#include <Windows.h>

#include <String.h>

#include <Stdio.h>

LRESULT CALLBACK WindowFunc(HWND, UINT,

WPARAM, LPARAM);

char szWinName[]="МоеОкно"; // Имя класса окна

char str[80]="Пример"; // Буфер для строки вывода

int WINAPI WinMain(HINSTANCE hThisInst,

HINSTANCE hPrevInst,

LPSTR lpszArgs,

int nWinMode)

{

HWND hwnd;

MSG msg;

WNDCLASS wcl; // Определить класс окна

wcl.hInstance=hThisInst; // Дескриптор приложения

wcl.lpszClassName=szWinName; // Имя класса окна

wcl.lpfnWndProc=WindowFunc; // Функция окна

wcl.style=0; // Стиль по умолчанию

wcl.hIcon=LoadIcon(NULL,IDI_APPLICATION);// Иконка

wcl.hCursor=LoadCursor(NULL,IDC_ARROW); // Курсор

wcl.lpszMenuName=NULL; // Без меню

wcl.cbClsExtra=0; // Без дополнительной информации

wcl.cbWndExtra=0;

wcl.hbrBackground=

(HBRUSH)GetStockObject(WHITE_BRUSH); //Белый фон

if(!RegisterClass(&wcl)) // Регистрируем класс окна

return 0;

hwnd=CreateWindow(szWinName, // Создать окно

"Обработка сообщений WM_PAINT",

WS_OVERLAPPEDWINDOW, // Стиль окна

CW_USEDEFAULT, // x-координата

CW_USEDEFAULT, // y-координата

CW_USEDEFAULT, // Ширина

CW_USEDEFAULT, // Высота

HWND_DESKTOP, // Нет родител. окна

NULL, // Нет меню

hThisInst,// Дескриптор приложения

NULL); // Нет дополнит. аргументов

ShowWindow (hwnd, nWinMode); // Показать окно

UpdateWindow (hwnd); // и перерисовать

 

while(GetMessage(&msg,NULL,0,0)) // Запустить цикл

{ // обработки сообщений

TranslateMessage(&msg); // Разреш. исп. клавиатуры

DispatchMessage (&msg); // Вернуть управл. Windows

}

return msg.wParam;

}

 

// Следующая функция вызывается операционной

// системой Windows и получает в качестве

// параметров сообщения из очереди сообщений

// данного приложения

LRESULT CALLBACK WindowFunc(HWND hwnd,

UINT message,

WPARAM wParam,

LPARAM lParam)

{

HDC hdc;

PAINTSTRUCT paintstruct;

switch(message)

{

case WM_CHAR: // Обработка нажатия клавиши

hdc=GetDC(hwnd); // Для получ. контекста устр-ва

TextOut(hdc, 1, 1, " ", 4); // Стереть символ

sprintf(str,"%c",(char)wParam); // Запись симв.

TextOut (hdc, 1, 1, str, strlen(str)); // Вывод

ReleaseDC (hwnd, hdc); // Освободить контекст

break;

case WM_PAINT: // Перерисовка рабочей области

hdc=BeginPaint(hwnd,&paintstruct);// Получить DC

TextOut(hdc,1,1,str,strlen(str));//Вывести буфер

EndPaint(hwnd, &paintstruct); // Освободить DC

break;

case WM_DESTROY: // Завершение программы

PostQuitMessage (0);

break;

default:

// Все сообщения, не обрабатываемые в

// данной функции, направляются на обработку

// по умолчанию

return DefWindowProc(hwnd,message,

wParam,lParam);

}

return 0;

}

 

Прежде чем продолжить чтение, скомпилируйте и повторно запустите эту про­грамму. Попробуйте ввести несколько символов, затем минимизируйте и снова раскройте окно. Вы увидите, что каждый раз при перерисовке окна последний введенный символ также перерисовывается. Заметьте, что внешний массив str инициализируется как слово "Пример", и эта строка отображается в начале работы программы. Так происходит потому, что при создании окна оно получает сообщение WM_PAINT. Далее, если окно не свертывать, графический «остаток» этого слова будет виден на экране.

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

Зная механизм перерисовки содержимого окна, Вы должны всегда использовать его в своих программах. В реальных программах перерисовка информации произво­дится, как правило, одним из трех способов.

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

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

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

 




Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2017-03-31 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: