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

3.5. Генерация сообщения wm_paint

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

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

Чтобы заставить Windows послать сообщение WM_PAINT, программа должна вызвать функцию API InvalidateRect(), имеющую следующий прототип:

BOOL InvalidateRect(HWND hwnd,

CONST RECT *lpRect,

BOOL fErase);

Здесь hwnd – это дескриптор окна, которому должно быть послано сообщение WM_PAINT, lpRect – указатель на структуру RECT, задающую прямоугольную область в окне, которая должна быть перерисована. Если lpRect равен NULL, окно перерисовывается полностью. Значение флага fErase определяет необходимость пере­рисовки заполнения окна. Если fErase не равен нулю, вначале выполняется перери­совка заполнения, т.е. содержимое перерисовываемой области вначале полностью стирается; иначе перерисовка заполнения не производится. В случае успешного завершения функция возвращает ненулевое значение. Как правило, эта функция всегда завершается успешно.

Вызов InvalidateRect() приводит к тому, что Windows отмечает окно как подле­жащее перерисовке. Это, в свою очередь, означает, что Windows должна послать программе сообщение WM_PAINT.

Пример 3-4. Ниже приводится измененная версия предыдущего примера, в которой весь свой вывод осуществляет при обработке сообщения WM_PAINT. При обработке других сообщений готовится необходимая информация для вывода, а затем вызывается функция InvalidateRect().

// Каркасная программа для Windows, осуществляющая

// весь вывод при обработке сообщения WM_PAINT

#include <Windows.h>

#include <String.h>

#include <Stdio.h>

LRESULT CALLBACK WindowFunc(HWND, UINT,

WPARAM, LPARAM);

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

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

int X=1, Y=1; // Координаты строки на экране

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, // Создать окно

"Обработка сообщений мыши",

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: // Обработка нажатия клавиши

X=Y=1; // Ввод отобразить в левом верхнем углу

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

InvalidateRect(hwnd,NULL,1); // Перерисов. экран

break;

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

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

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

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

break;

case WM_RBUTTONDOWN: // Нажата правая кнопка мыши

strcpy(str,"Нажата ПРАВАЯ кнопка");

X = LOWORD(lParam); // В X и Y записываются

Y = HIWORD(lParam); // текущие координаты мыши

InvalidateRect(hwnd,NULL,1); // Перерисов. экран

break;

case WM_LBUTTONDOWN: // Нажата левая кнопка мыши

strcpy(str,"Нажата ЛЕВАЯ кнопка");

X = LOWORD(lParam); // В X и Y записываются

Y = HIWORD(lParam); // текущие координаты мыши

InvalidateRect(hwnd,NULL,1); // Перерисов. экран

break;

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

PostQuitMessage(0);

break;

default:

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

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

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

return DefWindowProc(hwnd,message,

wParam,lParam);

}

return 0;

}

Заметьте, что в новой программе добавлены две глобальные переменные X и Y, сохраняющие позицию, с которой будет выводиться текст при обработке сообщения WM_PAINT.

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

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