Поcобие_БЕЛОВ_Графический_интерфейс_API
.pdf91
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,strlen(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, использовалась ранее.
Эта функция объявлена следующим образом:
92 BOOL UpdateWindow( HWND hwnd);
Она посылает сообщение WM_PAINT непосредственно функции окна hwnd. При успешном выполнении функция UpdateWindow возвращает ненулевое значение, иначе – нуль. Обычно ее вызывают для немедленной перерисовки области обновления.
Функция InvalidateRect добавляет прямоугольник в область перерисовки окна hwnd. Она объявлена следующим образом:
BOOL InvalidateRect( HWND hwnd, CONST RECT lpRect, BOOL bErase);
Параметр hwnd указывает на обновляемое окно. Если 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. Перерисовка окна после нажатия левой клавиши
93
мыши.
#include <windows.h>
BOOL RegClass(WNDPROC, LPCTSTR, UINT); LRESULT CALLBACK WndProc(HWND,UINT,WPARAM, LPARAM);
HINSTANCE hInstance;
char |
szClass[ ]="OutputClass2"; |
char |
szText[50]="Teкст по умолчанию"; |
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; HWNDhwnd; ::hInstance=hInstance;
if (!RegClass(WndProc, szClass,COLOR_WINDOW)) return FALSE;
hwnd = CreateWindow(szClass, "Вывод текста", 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 ex, cy;
94
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,strlen(szText)); EndPaint(hwnd,&ps);
return 0;
}
case WM_LBUTTONDOWN:
{ strcpy(szText,"Haжaтa левая клавиша мыши"); 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);
3.2. Виды контекста отображения
Существуют следующие виды контекста отображения:
•общий;
•для класса окон;
95
•личный;
•родительский;
•для окна.
Способы получения и освобождения контекста отображения зависят от вида контекста. Каждый контекст имеет свои особенности и назначение.
Общий контекст отображения. Этот контекст отличает наиболее высокая скорость доступа к нему. Для получения общего контекста вызывают функцию BeginPaint (при обработке сообщения WM_PAINT) или GetDC (для рисования при обработке других сообщений). Стиль класса окна с общим контекстом отображения не может содержать значения CS_OWNDC, CS_PARENTDC или
CS_CLASSDC.
Функция GetDC возвращает контекст отображения для рабочей области окна hwnd:
HDC GetDC( HWND hwnd);
Параметры возвращаемого контекста зависят от стиля класса указанного окна. Для общего контекста функция GetDC устанавливает заданные по умолчанию атрибуты, а параметры контекста отображения класса окон или личного контекста отображения функция GetDC оставляет неизменными. Если hwnd=NULL, то возвращается контекст видеомонитора с началом координат в левом верхнем углу экрана. В последнем случае допускается вывод в любом месте экрана.
При ошибках функция GetDC возвращает NULL.
Эту функцию вызывают, если требуется вывод в окно во время обработки других сообщений без отправления сообщения
WM_PAINT.
Для освобождения общего контекста отображения, полученного функцией GetDC, вызывают функцию ReleaseDC. Контекст отображения для класса окон и личный контекст отображения освобождать не обязательно. Функция ReleaseDC освобождает только общий контекст отображения или контекст отображения для окна:
int ReleaseDC( HWND hwnd, HDC hdc);
Здесь hwnd – дескриптор окна, чей контекст должен быть освобожден, a hdc – освобождаемый контекст отображения.
Если контекст освобожден, возвращаемое значение 1, иначе – нуль.
96
Приложения вызывают функцию ReleaseDC для каждого вызова функции GetWindowDC и для каждого вызова функции GetDC.
Повторно обращаем ваше внимание на необходимость своевременного освобождения общего контекста отображения.
Задача. При обработке сообщения WM_PAINT в центре рабочей области окна малиновым цветом шрифта на кремовом фоне вывести строку «Вывод при обработке сообщения WM_PAINT». После нажатия левой клавиши мыши на 60 пикселей выше синим цветом шрифта на желтом фоне вывести строку «Вывод при обработке сообщения WM_LBUTTONDOWN».
Листинг 3.3. Вывод текста при обработке различных сообщений.
#include <windows.h>
BOOL RegClass(WNDPROC, LPCTSTR, UINT); LRESULT CALLBACK WndProc(HWND,UINT,WPARAM, LPARAM);
HINSTANCE hInstance; char szClass[]="OutputClass";
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{MSG msg; HWND hwnd;
::hInstance=hInstance;
if (!RegClass(WndProc, szClass, COLOR_WINDOW)) return FALSE;
hwnd = CreateWindow(szClass, "Вывод текста", 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)
97
{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 ex, cy; switch (msg) {
case WM_SIZE:
{ cx=LOWORD(lParam); cy=HIWORD(lParam); return 0;
}
case WM_PAINT:
{ char szText[ ]="Вывод при обработке WM_PAINT"; PAINTSTRUCT ps;
HDC hdc=BeginPaint(hwnd,&ps); //Цветом вывода символов малиновый
SetTextColor(hdc,RGB(255,0,255)); //Цветом фона
// вывода символов выбираем кремовый
SetBkGolor(hdc,RGB(255,251,240)); SetTextAlign(hdc,TA_CENTER); TextOut(hdc,cx/2,cy/2,szText,strlen(szText)); EndPaint(hwnd,&ps);
return 0;
}
caseWM_LBUTTONDOWN:
{ char szText[]="Обработка WM_LBUTTONDOWN"; HDC hdc=GetDC(hwnd);
//Цветом вывода символов выбираем синий
SetTextColor(ndc,RGB(0, 0,255));
98
//Цветом фона вывода символов выбираем желтый
SetBkColor(hdc,RGB(255,255,0));
SetTextAlign(hdc,TA_CENTER); TextOut(hdc,cx/2,cy/2-60,szText,strlen(szText)); ReleaseDC(hwnd, hdc);
return 0;
}
case WM DESTROY: { PostQuitMessage(0); return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
После запуска этого приложения на экране появляется окно приложения с заголовком «Вывод текста». В центре рабочей области окна малиновым цветом шрифта на кремовом фоне отображен текст «Вывод при обработке сообщения WM_PAINT.
Если нажать левую клавишу мыши, на 60 пикселей выше этой строки появится еще одна строка «Обработка WM_LBUTTONDOWN» – синим цветом шрифта на желтом фоне.
Если переместить окно приложения или изменить его размеры, то на экране останется только та строка, которая выводится при обработке сообщения WM_PAINT. Вторая строка исчезнет. Это объясняется тем, что при необходимости перерисовки содержимого окна операционная система посылает сообщение WM_PAINT. После перерисовки фона рабочей области в окне приложения появится тот текст, который выводится при обработке сообщения WM_PAINT. Результаты вывода при обработке других сообщений стираются и не восстанавливаются.
Контекст отображения для класса окон
Можно создать единственный контекст отображения для всех окон некоторого класса. Для этого при регистрации класса указывают стиль CS_CLASSDC, тогда все окна этого класса будут пользоваться одним общим контекстом отображения.
Приложения, однажды получив контекст отображения для класса окон, могут не освобождать его. Причем вызов функций EndPaint и ReleaseDC не освобождает такой контекст (хотя и не
99
вредит работе приложения). Для сохранения единого стиля работы с контекстами рекомендуется всегда вызывать эти функции.
Контекст отображения для класса окон создают один раз. Если создано несколько окон этого класса, область ограничения и начало системы физических координат вывода автоматически настраиваются на то окно, которое использует контекст отображения. Однако если на базе класса стиля CS_CLASSDC приложение создало только одно окно, оно может получить контекст отображения для класса окон один раз и не освобождать его.
Таким образом, контекст отображения для класса окон повышает производительность вывода в окна тем, что не требует настройку многочисленных атрибутов контекста отображения после каждого вызова функции BeginPaint или EndPaint.
Задача. Для окон класса стиля CS_CLASSDC создать единый контекст и установить его атрибуты по умолчанию. После нажатия левой клавиши мыши изменить атрибуты контекста, а после нажатия правой клавиши – восстановить исходные значения атрибутов.
Листинг 3.4. Установка атрибутов контекста для класса по умолчанию, изменение атрибутов и восстановление их исходных значений.
#include <windows.h>
BOOL RegClass(WNDPROC, LPCTSTR, UINT); LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,
LPARAM);
void ContAttr(HWND hwnd); HINSTANCE hInstance;
char szClass[]="ClassContext;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int hCmdShow)
{ MSG msg; HWND hwnd1,hwnd2; ::hInstance=hInstance;
if (!RegClass(WndProc, szClass,COLOR_WINDOW)) return FALSE;
hwnd1 = CreateWindow(szClass, "Первое окно", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
100
hInstance, NULL);
if (!hwnd1) return FALSE;
hwnd2 = CreateWindow(szClass, "Второе окно", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT. CW_USEDEFAULT, 0,0, hInstance, NULL);
if (!hwnd2) return FALSE;
//Устанавливаем исходные атрибуты контекста
ContAttr(hwnd1); while(GetMessage(&msg, 0,0,0))
DispatchMessage(&msg); return msg.wParam; }
BOOL RegClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)
{WNDCLASSwc; wc.cbClsExtra = wc.cbWndExtra = 0; wcstyle = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC; wc.lpfnWndProc = Proc;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(brBackground +1); wc.lpszMenuName = NULL;
wc.lpszClassName = szName; return (RegisterClass(&wc) != 0);
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{static short ex, cy; switch (msg)
{caseWM_SIZE:
{cx=LOWORD(lParam);
cy=HIWORD(lParam); return 0;
}
case WM_PAINT:
{ char szText[ ]= "Вывод с атрибутами контекста класса";
PAINTSTRUCT ps;
HDC hdc=BeginPaint(hwnd,&ps); TextOut(hdc,cx/2,cy/2,szText,stiien(szText));
