- •Московская финансово-промышленная академия
- •Содержание
- •Глава 1. Модель программирования приложений
- •1.1. Потребительские свойства Windows
- •1.2. Процессы в Windows и потоковая многозадачность
- •1.3. Динамические библиотеки
- •1.4. Программное обеспечение для создания Win-приложений
- •Спецификация префиксов венгерской нотации
- •Глава 2. Обзор возможностей программирования
- •2.1. Общий взгляд на программирование в Windows
- •2.2. Взаимодействие Windows с программой
- •2.3. Win32 api: прикладной интерфейс для Windows
- •2.4. Компоненты окна
- •2.5. Основы приложений Windows
- •2.6. Каркас приложения Windows
- •2.7. Определение класса окна
- •Значения параметра lpszName
- •Наиболее употребляемые макросы для встроенных курсоров
- •Типы системных кистей
- •2.8. Создание окна
- •Наиболее распространенные стили
- •Параметры способа отображения nHow
- •2.9. Цикл обработки сообщений
- •2.10. Оконная функция
- •Типы префиксов
- •Глава 3. Обработка сообщений Windows
- •3.1. Что такое сообщения?
- •3.2. Обработка нажатая клавиш
- •Битовая карта lParam
- •3.3. Обработка сообщений wm_paint
- •3.4. Обработка сообщений «мыши»
- •3.5. Генерация сообщения wm_paint
- •3.6. Генерация сообщений таймера
- •Глава 4. Ресурсы и меню
- •4.1. Окна сообщений MessageBox
- •Значения функции MessageBox
- •Значения wMbType
- •4.2. Представляем меню
- •4.3. Использование ресурсов
- •Параметры menu
- •Параметры элементов меню
- •4.4. Включение меню в программу. Обработка команд
- •4.5. Включение акселераторов сменю
- •4.6. Загрузка таблицы акселераторов
- •Глава 5. Создание диалогов
- •5.1. Взаимодействие Win-диалогов с пользователем
- •5.2. Модальные диалоги: обработка сообщений
- •5.3. Активизация и создание простейшего диалога
- •5.4. Определение ресурсов диалога
- •Стили диалога
- •5.5. Оконная функция диалога
- •5.6. Основы работы со списками
- •Типы сообщений
- •5.7. Инициализация списка и выбор элементов
- •5.8. Окно ввода
- •5.9. Использование немодального диалога
- •Глава 6. Графические образы, иконки и курсоры
- •6.1. Иконка и курсор
- •6.2. Определение малой иконки
- •6.3. Работа с растровыми изображениями
- •Значения параметра dwRaster
- •6.4. Работа с несколькими растровыми изображениями
- •Глава 7. Более подробно об элементах управления
- •7.1. Работа с контрольными переключателями
- •7.2. Статические элементы
- •7.3. Работа с селекторными кнопками
- •7.4. Линейки прокрутки
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. Тем не менее программы вывода информации, основанные на обработке других сообщений, не являются неверными. Просто такие подходы могут в некоторых случаях оказаться далеко не лучшими.