- •Приклад створення типового Windows-додатка
- •1. Робота з компілятором
- •2.2 Точка входу в програму
- •Int winapi WinMain (hinstance hInstance, hinstance hPrevInstance,
- •2.3 Реєстрація класу вікна
- •Поля структури wndclass:
- •2.4 Створення вікна
- •2.5 Відображення вікна
- •2.6 Цикл обробки черги повідомлень
- •2.7 Віконна процедура
- •2.8 Обробка повідомлень
- •2.9 Повідомлення wm_paint
- •2.10 Видалення вікна, повідомлення wm_destroy
- •Практична частина
- •Контрольні питання :
2.9 Повідомлення wm_paint
Повідомлення WM_PAINT украй важливо для програмування під Windows. Воно повідомляє програмі, що частина чи вся робоча область вікна недійсна (invalid), і її варто перемалювати.
Розглянемо ситуації, коли робоча область може ставати недійсною.
При першому створенні вікна недійсна вся робоча зона (інша назва – клієнтська частина) вікна, оскільки програма ще нічого не намалювала. Повідомлення WM_PAINT, що посилається, коли додаток викликає функцію UpdateWindow, змушує віконну процедуру щось намалювати в робочій області.
Коли користувач змінює розмір вікна, у стилі якого задані прапори CS_HREDRAW і CS_VREDRAW, робоча область також стає недійсною. Операційна система слідом за цим посилає у віконну процедуру повідомлення WM_PAINT.
Коли користувач мінімізує вікно програми, а потім знову відновлює до колишнього розміру, то в Windows уміст робочої області не зберігається (у графічному середовищі це б привело до того, що довелося б зберігати занадто багато даних). Замість цього Windows робить недійсним усе вікно. Потім віконна процедура одержує повідомлення WM_PAINT і сама відновлює вміст вікна.
Коли користувач переміщає вікна так, що вони перекриваються, Windows не зберігає ту частину вікна, що закривається іншим вікном. Коли ця частина пізніше відкривається, Windows відзначає цю область як недійсну. Віконна процедура одержує повідомлення WM_PAINT для відновлення вмісту вікна.
Якщо по логіці роботи додатка при обробці того чи іншого повідомлення потрібно змінити уміст вікна, то додаток може саме за допомогою функції InvalidateRect оголосити будь-яку область вікна як недійсну (тобто потребуючу відновлення):
InvalidateRect(hWnd,NULL,TRUE);
Зауваження. Перший параметр функції InvalidateRect є ідентифікатором вікна, для якого виконується операція. Другий параметр - покажчик на структуру типу RECT, що визначає прямокутну область, що підлягає відновленню (якщо він дорівнює NULL, те недійсної з'являється уся внутрішня частина вікна). Третій параметр визначає необхідність стирання фону вікна (якщо параметр заданий як TRUE, фон вікна підлягає стиранню).
Отже,
Повідомлення WM_PAINT посилається операційною системою вікну, коли його частина вимагає перемальовування, і в черзі повідомлень потоку, що володіє цим вікном, не знаходиться інших неопрацьованих повідомлень.
Якщо вікно містить одну чи кілька областей, що підлягають відновленню, то додаток одержує одне повідомлення WM_PAINT, у якому визначена область, що охоплює всі зазначені області.
Обробка повідомлення WM_PAINT майже завжди починається з виклику функції BeginPaint, а закінчується EndPaint.
Додайте цей код:
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
RECT rect ;
…
case WM_PAINT: // Обновити вміст клієнтської області вікна
{
hdc = BeginPaint (hwnd, &ps) ;
GetClientRect (hwnd, &rect) ;
DrawText (hdc, "Hello, Windows!", -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
EndPaint (hwnd, &ps) ;
break;
case WM_DESTROY :
…
В обох функціях перший параметр – це дескриптор вікна додатка, а другий – це покажчик на структуру типу PAINTSTRUCT. У цій структурі міститься деяка інформація, яку віконна процедура може використовувати для малювання в робочій області вікна.
Зокрема, одне з полів цієї структури являє собою наймаленький прямокутник, що містить всі області вікна, що вимагають перемальовування. Обмеживши свої дії по малюванню тільки цією прямокутною областю, додаток може прискорити процес перемальовування.
При обробці виклику BeginPaint, Windows
обновляє фон робочої області за допомогою кисті, що вказувалася при реєстрації класу вікна;
робить усю робочу область дійсною (не потребуючою перемальовування);
повертає дескриптор контексту пристрою (цей дескриптор необхідний для виводу в робочу область тексту і графіки).
При використанні дескриптора контексту пристрою, що повертається функцією BeginPaint, додаток не може малювати поза робочою областю. Функція EndPaint звільняє дескриптор пристрою, після чого його не можна використовувати.
Зауваження 1. Функцію BeginPaint варто викликати тільки у відповідь на повідомлення WM_PAINT. Кожен виклик цієї функції повинний сполучатися з наступним викликом функції EndPaint.
Зауваження 2. Тому що додаток практично ніколи при обробці повідомлення WM_PAINT не знає розмірів усієї своєї клієнтської області, то перед малюванням воно може одержати цю інформацію за допомогою функції:
BOOL GetClientRect(HWND hWnd, LPRECT rect);
Перший параметр – дескриптор вікна, другий – покажчик на змінну типу RECT, у цю змінну функція GetClientRect поміщає інформацію про розмір робочої області в пікселях.
Функція DrawText() призначена для виводу тексту на екран у визначеній позиції. У загальному вигляді вона виглядає так:
int DrawText(
HDC hdc, // дескриптор контексту дисплея
LPCTSTR lpString, // покажчик на відображуваний рядок
int nCount, // довжина рядка
LPRECT rect, // куди виводити
UINT uFormat ); // прапори форматованого відображення тексту
Якщо lpString указує на рядок, що закінчується 0, то nCount=-1. DT_SINGLELINE означає, що текст розташовується в один рядок, тобто не містить символів переводу рядка і повернення каретки. DT_CENTER і DT_VCENTER визначають положення рядка в межах клієнтської області (тому що перед використанням цієї функції ми викликали функцію визначення робочої області додатка — GetClientRect (hwnd, &rect); ) — у центрі вікна.
Функція TextOut() призначена для виводу рядка символів на екран у зазначеній позиції, використовуючи поточний шрифт. У загальному вигляді вона виглядає так:
BOOL TextOut(
HDC hdc, // дескриптор контексту дисплея
int nXStart, // x-координата початкової позиції
int nYStart, // y- координата початкової позиції
LPCTSTR lpString, // покажчик на відображуваний рядок
int cbString // кількість символів у рядку
);
