
- •Московская финансово-промышленная академия
- •Содержание
- •Глава 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.3. Обработка сообщений 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.