Сообщение WM_PAINT

Стремление описывать вывод в окно при обработке сообщения WM_PAINT объясняется следующим. Windows следит за изменением расположения окон и при необходимости перерисовки окна посылает функции окна сообщение WM_PAINT. Функция окна при обработке этого сообщения перерисовывает все окно или указанные части.

Сообщение WM_PAINT обрабатывают следующим образом:

case WM_PAINT:

{

PAINTSTRUCT ps;

HDC hdc = BeginPaint(hwnd, &ps);

// Здесь настраивают контекст отображения

// и выводят в окно

EndPaint(hwnd, &ps);

return 0;

}

Структура PAINTSTRUCT описана следующим образом:

typedef struct {

НDС hdc;

BOOL fErase;

RECT rcPaint;

BOOL fRestore;

BOOL fIncUpdate;

BYTE rgbReserved[16];

} PAINTSTRUCT;

Поля переменной ps заполняет функция BeginPaint. После ее вызова поле hdc структуры ps содержит дескриптор контекста отображения (тот же, который возвращает функция BeginPaint). Поле rcPaint содержит координаты прямоугольной области обновления. Поле fErase определяет необходимость стирания фона области обновления. Если fErase = TRUE, фон окна стирается, иначе фон окна не изменяется. Остальные поля использует операционная система, приложение не должно изменять их содержимое.

После выполнения операций вывода приложение освобождает используемые ресурсы – вызывает функцию EndPaint.

Задача. В центре рабочей области окна вывести текст.

Листинг 3.1 содержит решение данной задачи.

Листинг 3.1. Вывод текста в центре рабочей области.

#include <windows.h>

#include <tchar.h>

BOOL RegClass(WNDPROC, LPCTSTR, UINT);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

HINSTANCE hInstance;

TCHAR szClass[] = TEXT("OutputClass");

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)

{

MSG msg;

HWND hwnd;

hInstance = hInst;

if (!RegClass(WndProc, szClass, COLOR_WINDOW))

return FALSE;

hwnd = CreateWindow(szClass, TEXT("Вывод текста"),

WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, NULL);

if (!hwnd) return FALSE;

ShowWindow(hwnd, SW_SHOWMAXIMIZED);

UpdateWindow(hwnd);

while(GetMessage(&msg, 0,0, 0)) DispatchMessage(&msg);

return msg.wParam;

}

BOOL RegClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)

{

WNDCLASS wc;

wc.style = CS_HREDRAW | CS_VREDRAW;

wc.cbClsExtra = wc.cbWndExtra = 0;

wc.lpfnWndProc = Proc;

wc.hInstance = hInstance;

wc.lpszClassName = szName;

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(brBackground +1);

wc.lpszMenuName = NULL;

return (RegisterClass(&wc)!= 0);

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

TCHAR szText[] = TEXT("Выводим какой-либо текст");

static short cx, cy;

switch (msg)

{

case WM_SIZE:

{

cx=LOWORD(lParam); cy=HIWORD(lParam);

return 0;

}

case WM_PAINT:

{

PAINTSTRUCT ps;

HDC hdc = BeginPaint(hwnd, &ps);

//Настриваем атрибуты вывода текста

SetTextColor(hdc, RGB(255, 0, 0));

SetBkColor(hdc, RGB(0, 255, 255));

SetTextAlign(hdc, TA_CENTER);

//Выводим текст

TextOut(hdc, cx/2, cy/2, szText, _tcslen(szText));

EndPaint(hwnd, &ps);

return 0;

}

case WM_DESTROY: { PostQuitMessage(0); return 0; }

}

return DefWindowProc(hwnd, msg, wParam, lParam);

}

Обратите внимание, что в стиле класса окна, обрабатывающего сообщение WM_PAINT, нужно указывать, что оно должно перерисовывать содержимое при изменении размеров окна:

wc.style = CS_HREDRAW | CS_VREDRAW;

Окна класса с таким стилем получают сообщение WM_PAINT при изменении их размеров.

При обработке сообщения WM_PAINT добавились операторы настраивания атрибутов контекста отображения и вывода в окно:

//Настриваем атрибуты вывода текста

SetTextColor(hdc, RGB(255, 0, 0));

SetBkColor(hdc, RGB(0, 255, 255));

SetTextAlign(hdc, TA_CENTER);

//Выводим текст

TextOut(hdc, cx/2, cy/2, szText, strlen(szText));

Функции настраивания атрибутов и вывода в окно рассматриваются ниже.

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

Одна из функций, которые посылают сообщение WM_PAINT, а именно UpdateWindow, использовалась ранее.

Эта функция объявлена следующим образом:

BOOL UpdateWindow(HWND hwnd);

Она посылает сообщение WM_PAINT непосредственно функции окна hwnd. В случае успешного выполнения функция UpdateWindow возвращает ненулевое значение, иначе – 0. Обычно ее вызывают для немедленной перерисовки области обновления.

Функция InvalidateRect добавляет прямоугольник в область перерисовки окна hwnd. Она объявлена следующим образом:

BOOL InvalidateRect(HWND hwnd, CONST RECT lpRect, BOOL bErase);

Параметр hwnd указывает на обновляемое окно. Если это параметр указывает на NULL, перерисовывают все окна. Параметр lpRect указывает на нуждающийся в обновлении прямоугольник в рабочей области. Если lpRect = NULL, то нужно обновить всю рабочую область окна hwnd. Параметр bErase определяет, нужно ли перекрасить фон указанной прямоугольной области. Если bErase = TRUE, фон перекрашивают, иначе фон остается неизменным.

В случае успешного выполнения функция возвращает ненулевое значение.

Добавляемые прямоугольники накапливаются до обработки сообщения WM_PAINT. В качестве единой области перерисовки Windows вычисляет один прямоугольник, который охватывает все добавленные прямоугольники.

Функция ValidateRect удаляет прямоугольную область из списка прямоугольников перерисовки. Прототип этой функции:

BOOL ValidateRect(HWND hwnd, CONST RECT lpRect);

Параметр hwnd указывает на окно, из области перерисовки которого исключается прямоугольник. Если этот параметр NULL, Windows перерисовывает все окна – посылает сообщения WM_ERASEBKGND и WM_NCPAINT функциям всех окон. Параметр lpRect указывает на прямоугольник, который будет удален от области перерисовки. Если lpRect = NULL, из области обновления удаляют все прямоугольники.

В случае успешного выполнения функция возвращает ненулевое значение.

Функция BeginPaint из области обновления удаляет всю рабочую область окна.

Задача. В центре рабочей области окна вывести строку "Текст по умолчанию". После нажатия левой клавиши мыши содержимое этой строки сменить на текст "Нажата левая клавиша мыши".

Листинг 3.2. Перерисовка окна после нажатия левой клавиши мыши

#include <windows.h>

#include <tchar.h>

BOOL RegClass(WNDPROC, LPCTSTR, UINT);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

HINSTANCE hInstance;

TCHAR szClass[] = TEXT("OtputClass2");

TCHAR szText[50] = TEXT("Текст no умолчанию");

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)

{

MSG msg;

HWND hwnd;

hInstance = hInst;

if (!RegClass(WndProc, szClass, COLOR_WINDOW))

return FALSE;

hwnd = CreateWindow(szClass, TEXT("Вывод текста"),

WS_OVERLAPPEDWINDOW | WS_VISIBLE,

CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

0, 0, hInstance, NULL);

if (!hwnd) return FALSE;

while(GetMessage(&msg, 0, 0, 0)) DispatchMessage(&msg);

return msg.wParam;

}

BOOL RegClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)

{

WNDCLASS wc;

wc.style = CS_HREDRAW | CS_VREDRAW;

wc.cbClsExtra = wc.cbWndExtra = 0;

wc.lpfnWndProc = Proc;

wc.hInstance = hInstance;

wc.lpszClassName = szName;

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(brBackground +1);

wc.lpszMenuName = NULL;

return (RegisterClass(&wc)!= 0);

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

static short cx, cy;

switch (msg)

{

case WM_SIZE:

{ cx=LOWORD(lParam); cy=HIWORD(lParam); return 0; }

case WM_PAINT:

{

PAINTSTRUCT ps;

HDC hdc = BeginPaint(hwnd, &ps);

SetTextColor(hdc, RGB(255, 0, 0));

SetBkColor(hdc, RGB(0,255, 255));

SetTextAlign(hdc, TA_CENTER);

TextOut(hdc, cx/2, cy/2, szText, _tcslen(szText));

EndPaint(hwnd,&ps);

return 0;

}

case WM_LBUTTONDOWN:

{

_tcscpy(szText, TEXT("Нажата левая клавиша мыши"));

InvalidateRect(hwnd, NULL, TRUE);

return 0;

}

case WM_DESTROY: { PostQuitMessage(0); return 0;}

}

return DefWindowProc(hwnd, msg, wParam, lParam);

}

Произошли следующие изменения:

1. Переменная szText описана глобально. При "вызове" функции окна эта переменная сохраняет последнее присвоенное значение.

2. При обработке сообщения WM_LBUTTONDOWN в переменную szText записывается текст " Нажата левая клавиша мыши " и в область перерисовки добавляется вся рабочая область:

strcpy(szText, "Нажата левая клавиша мыши");

InvalidateRect(hwnd, NULL, TRUE);


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: