Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Обработка сообщений 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.

 


3.4. Обработка сообщений «мыши»

 

Поскольку Windows широко использует ввод мыши, все Windows-программы должны обрабатывать сообщения мыши. Имеется несколько типов таких сообщений.

В этом разделе используются два наиболее часто употребляемых сообщения мыши – WM_LBUTTONDOWN и WM_RBUTTONDOWN, которые поступают при нажатии соответственно левой и правой кнопок мыши.

Для начала в оператор switch оконной функции необходимо добавить обработку этих сообщений так, как показано ниже:

 

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

hdc = GetDC(hwnd); // Получить DC

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

TextOut(hdc,

LOWORD(lParam), HIWORD(lParam),

str, strlen(str));

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

break;

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

hdc = GetDC(hwnd); // Получить DC

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

TextOut(hdc,

LOWORD(lParam), HIWORD(lParam),

str, strlen(str));

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

break;

 

При нажатии кнопки мыши координаты текущей позиции курсора x и y передаются соответственно в LOWORD(lParam) и HIWORD(lParam). Программа, обрабаты­вающая сообщения мыши, использует эти координаты для вывода на экран соответ­ствующей текстовой строки. То есть каждый раз при нажатии кнопки мыши сообщение об этом будет выведено в текущей позиции курсора.

 

Пример 3-3. Далее следует полная программа обработки сообщений мыши.

 

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

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

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

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_RBUTTONDOWN: // Нажата правая кнопка мыши

hdc = GetDC(hwnd); // Получить DC

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

TextOut(hdc,

LOWORD(lParam), HIWORD(lParam),

str, strlen(str));

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

break;

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

hdc = GetDC(hwnd); // Получить DC

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

TextOut(hdc,

LOWORD(lParam), HIWORD(lParam),

str, strlen(str));

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

break;

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

PostQuitMessage(0);

break;

default:

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

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

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

return DefWindowProc(hwnd, message,

wParam, lParam);

}

return 0;

}

 

 

Результаты работы этой программы показаны на рис. 3.2.

Более подробно о сообщениях «мыши». Параметр wParam сообщений WM_LBUTTONDOWN и WM_RBUTTONDOWN содержит дополнительную информацию, представляющую собой комбинацию сле­дующих флагов:

 

MK_CONTROL

MK_SHIFT

MK_RBUTTON

MK_LBUTTON

MK_MBUTTON

 

Если в момент нажатия кнопки мыши была нажата клавиша [Ctrl], wParam будет содержать флаг MK_CONTROL. Если же в этот момент была нажата клавиша [Shift], wParam будет содержать флаг MK_SHIFT. Флаги MK_LBUTTON, MK_RBUTTON и MK_MBUTTON устанавливаются, если были нажаты соответственно левая, правая и средняя кнопки мыши. Параметр wParam может содержать комбинацию (т.е. одновременно более одного) этих флагов. Вы можете поэкспери­ментировать с сообщениями мыши и убедиться в этом.

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.