- •Лекция №4. Gdi – графический интерфейс устройства.
- •Контекст устройства
- •Отсеченный путь
- •Этот метод используется при обработке сообщения wm_paint. Контекст устройства получают вызовом функции BeginPaint, имеющей следующий прототип:
- •Пример: в центре рабочей области окна вывести текст.
- •Использование сообщения wm_paint
- •Функция ValidateRect
- •Пример 2.
- •Частные контексты устройства
- •Операции контекста устройства
- •Режимы отображения.
- •Отображаем картинку в окне:
Операции контекста устройства
1) Приложение контекстом устройства может выполнить ниже перечисленные операции:
2) Перечислить существующие графические объекты.
3) Выбрать новый графический объект.
4) Удалить существующие графические объекты.
5) Сохранить текущие графические объекты, их атрибуты и графические режимы.
6) Восстановить предварительно сохраненные графические объекты, их атрибуты и графические режимы.
Кроме того, приложение может использовать контекст устройства, чтобы:
1) Выяснить, как транслируется графический вывод данных.
2) Отменить длинные операции рисования (начатый потоком в многопоточном приложении).
3) Возвратить в исходное положение специфическое состояние принтера.
Режимы отображения.
Большинство функций, работающих с оконными координатами, определяют координаты относительно начала рабочей области окна, то есть от левего верхнего угла.
Единицы, в которых измеряются координаты, зависят от режима отображения (mapping mode), установленного для данного окна. Единицы измерения, зависящие от режима отображения, называют логическими единицами, а координаты в этом случае называют логическими координатами.
При выводе информации на конкретное устройство единицы логических координат преобразуются в физические единицы, которыми являются пиксели.
Идентификаторы, применяемые для обозначения режимов отображения.
Для установки текущего режима отображения используется функция SetMappingMode(), которая имеет следующий прототип:
WINGDIAPI int WINAPI SetMapMode(HDC, int);
Аргумент HDC – хэндл контекста устройства, для которого устанавливается данный режим.
Аргумент int – определяет задаваемый режим отображения. При создании окна по умолчанию устанавливается режим MM_TEXT, то есть все координаты исчисляются в пикселах.
Отображаем картинку в окне:
#include <windows.h>
LRESULT CALLBACK PaintWndProc(HWND,UINT,UINT,LONG);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
HWND hMainWnd;
char szClassName[] = "MyClass";
MSG msg;
WNDCLASSEX wc;
// Заполняем структуру класса окна
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = PaintWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_INFORMATION);
// Регистрируем класс окна
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, "Cannot register class", "Error", MB_OK);
return 0;
}
hMainWnd=CreateWindow(szClassName,"Должно быть фото...",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,
hInstance,NULL);
if (!hMainWnd)
{
MessageBox(NULL,"Не могу создать окно","Error",MB_OK);
return 0;
}
// Показываем наше окно
ShowWindow(hMainWnd,nCmdShow);
UpdateWindow(hMainWnd);
// Создаём цикл сообщений
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// Создаём оконную процедуру
LRESULT CALLBACK PaintWndProc(HWND hWnd,UINT Message,
UINT wParam,LONG lParam)
{
HDC hDC,hCompatibleDC;
PAINTSTRUCT PaintStruct;
HANDLE hBitmap,hOldBitmap;
RECT Rect;
BITMAP Bitmap;
switch(Message)
{
case WM_PAINT:
// Получаем контекст устройства
hDC=BeginPaint(hWnd,&PaintStruct);
// Загружаем bitmap, который будет отображаться в окне
hBitmap=LoadImage(NULL, "Foto118.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
// Получаем размерность загруженного bitmapа
GetObject(hBitmap,sizeof(BITMAP),&Bitmap);
// Создаём совместимый с контекстом окна контекст в памяти
hCompatibleDC=CreateCompatibleDC(hDC);
// Делаем загруженный из файла bitmap текущим в совместимом контексте
hOldBitmap=SelectObject(hCompatibleDC,hBitmap);
// Определяем размер рабочей области окна
GetClientRect(hWnd,&Rect);
// Копируем bitmap с совместимого на основной контекст с масштабированием
StretchBlt(hDC,0,0,Rect.right,Rect.bottom,hCompatibleDC,0,0,Bitmap.bmWidth,Bitmap.bmHeight,SRCCOPY);
// Делаем старый bitmap текущим
SelectObject(hCompatibleDC,hOldBitmap);
// Удаляем загруженный с диска bitmap
DeleteObject(hBitmap);
// Удаляем совместимый контекст
DeleteDC(hCompatibleDC);
// Освобождаем основной контекст, завершая перерисовку рабочей области окна
EndPaint(hWnd,&PaintStruct);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,Message,wParam,lParam);
}
Для отображения рисунка Foto125.bmp необходимо, чтобы этот файл находился в текущей директории Debug. Можно также указать адрес файла с изображением, если он находится не в текущей директории, например так:
D:\\Задания\\WinAPI\\Graf\\Debug
Функция WinMain() стандартна. В оконной функции PaintWndProc() обрабатывается сообщение WM_PAINT следующим образом:
1) Получаем хэндл контекста устройства посредством вызова функции BeginPaint(hWnd,&PaintStruct), где
hWnd – окно для которого получаем контекст отображения;
&PaintStruct – параметр, через который передаётся адрес структуры типа PAINTSTRUCT.
2) Получаем хэндл bitmap’а, который должен отображаться в окне вызывая функцию LoadImage(). Данная функция позволяет загружать графические образы как из ресурсов, записанных в исполняемом файле, так и из файлов, содержащих только изображения. Функция позволяет также управлять параметрами отображения и загрузки образа.
Эта функция имеет следующий прототип:
LoadImage(HINSTANCE hInst, LPCSTR lpszName, UINT bmImage, int w, int t, UINT fuLoad)
Аргумент hInst – хэндл программы. Если вместо хэндла программы указан NULL, то объект является предопределённым, то есть хранится в глубинах системы. В противном случае объект загружается откуда-то снаружи.
Аргумент lpszName – определяет загружаемый объект.
Аргумент fuLoad – содержит флаги, определяющие режим загрузки объекта. Если этот флаг установлен, то загрузка происходит из внешнего файла. Среди флагов есть занчение LR_LOADFROMFILE. От значения первого и последнего аргументов зависит как будет интерпретирован второй аргумент. Взаимодействие этих трёх аргументов объясняется в таблице.
fuLoad (флаг LR_LOADFROMFILE) |
hInst |
lpszName |
Не установлен |
NULL |
Идентификатор предопределённого объекта |
Не установлен |
Не NULL |
Имя ресурса |
Установлен |
NULL |
Имя файла, в котором содержится bitmap |
Установлен |
Не NULL |
Имя файла, в котором содержится bitmap |
Третий аргумент bmImage – тип образа, он может принимать значения IMAGE_BITMAP, IMAGE_CURSOR, IMAGE_ICON, IMAGE_ENHMETAFILE.
Четвёртый аргумент и пятый (w, t) указывают ширину и высоту иконки или курсора.
Флаги, определяющие параметры загрузки образа в память начинаются с букв LR и могут принимать следующие значения табл. 8:
Функция LoadImage() возвращает хэндл загруженного битмапа или NULL.
3) Получаем совместимый контекст в памяти с помощью функции CreateCompatibleDC(). Единственный аргумент этой функции – хэндл контекста (hDC), для которого создаётся совместимый контекст.
4) Делаем загруженный из файла bitmap текущим в совместимом контексте с помощью функции SelectObject(). Аргумент hCompatibleDC – хэндл контекста, в котором замещается текущий элемент. Второй – хэндл элемента, которым замещается текущий элемент (хэндл загруженного битмапа). То есть эта функция возвращает хэндл замещённого элемента и в последствии с этим элементом могут также производиться манипуляции.
5) Копируем bitmap с совместимого на основной контекст с масштабированием. Для копирования битмапа с одного контекста на другой используется функция StretchBlt(). Эта функция в файле wingdi.h описана следующим образом:
StretchBlt(HDC, int, int, int, int, HDC, int, int, int, int, DWORD);
Первые пять аргументов описывают тот прямоугольник на экране, в который будет вписан битмап (на рис. Он обозначен светло-серым цветом). Ту часть битмапа, которая будет вписана в прямоугольник на экране (на рисунке – пересекающаяся часть светло-серого и тёмно-серого прямоугольников), описывают следующие пят аргументов. И последний одиннадцатый аргумент – код растровой операции, описывает каким образом пиксели одного битмапа будут взаимодействовать с пикселами другого битмапа. Обратимся к рисунку.
Рисунок.
Предположим, что в регионе, обозначенном на рис. светло-серым цветом нужно отобразить битмап (обозначен на рисунке тёмно-серым цветом) или часть битмапа при необходимости сжав или растянув его.
Первый и шестой аргументы функции – хэндлы окна (hDC) и совместимого контекста (hCompatibleDC) соответственно. Второй (nXOriginDest) и третий (nYOriginDest) аргументы содержат смещение верхнего левого угла прямойгольника, в который будет вписываться битмап, относительно левой и верхней сторон рабочей области окна (так как мы при создании окна не меняли режим отображения, то текущий режим является установленным по умолчанию). Четвертый (nWidthDest) и пятый (nHeightDest) аргументы – ширина и высота этого прямоугольника. Седьмой (nXOriginSrc) и восьмой (nYOriginSrc) аналогичны второму и третьему аргументам. Девятый (nWidthSrc) и десятый (nHeightSrc) аргументы содержат ширину и высоту отображаемой части битмапа. Изменяя положение прямоугольников друг относительно друга, а также относительно окна, меняя их размеры, можно отобразить на экране любую часть или целый битмап.
Для того чтобы совместить битмап с рабочей областью окна необходимо, чтобы второй и третий аргумент функции StretchBlt были равны нулю. Четвёртый и пятый аргумент должны быть равны ширине и высоте рабочей области (ширину и высоту рабочей области можно получить с помощью функции GetClientRect(hWnd,&Rect)). Седьмой и восьмой аргументы равны нулю, девятый и десятый аргументы должны содержать ширину и высоту битмапа, которые можно получить, обратившись к функции GetObject.
Одиннадцатый аргумент функции StretchBlt() – это код растровой операции, то есть это код, который определяет, как при операции будут взаимодействовать биты, определяющие заливку и изображение совместимого контекста с изображением на действительном контексте.
6) Удаляем совместимый контекст;
7) Удаляем объект;
8) Удаляем контекст устройства.
