Приведенная ниже программа демонстрирует описанные выше графические функции. Эта программа использует технологию виртуального окна, которая рассматривалась в гл. 8. Она направляет весь вывод в контекст устройства памяти, содержимое которой затем копируется в реальное окно при обработке сообщения WM_PAINT. Этот прием позволяет автоматически обновлять содержимое окна при получении сообщения WM_PAINT.
Пример 9-1. Демонстрация основных графических функций:
// Демонстрация основных графических функций
#include <Windows.h>
#include <String.h>
#include <Stdio.h>
#include "Graph.h"
LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);
char szWinName[] = "МоеОкно"; // Имя класса окна
char str[255]; // Буфер строки вывода
int X=0, Y=0; // Текущие координаты строки
int maxX, maxY; // Размеры экрана
HDC memdc; // DC виртуального окна
HBITMAP hbit; // Растр - это виртуальное окно
HBRUSH hbrush, hOldbrush; // Дескрипторы кистей
HPEN hOldpen; // Дескриптор прежнего пера
HPEN hRedpen,hGreenpen,hBluepen,hYellowpen; // Перья
int WINAPI WinMain (HINSTANCE hThisInst,
HINSTANCE hPrevInst,
LPSTR lpszArgs,
int nWinMode)
{
HWND hwnd;
MSG msg;
WNDCLASS wcl;
HACCEL hAccel;
// Определить класс окна
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="MYMENU"; // Меню
wcl.cbClsExtra=0; // Без дополнительной
wcl.cbWndExtra=0; // информации
// Определить заполнение окна белым цветом
wcl.hbrBackground=
(HBRUSH)GetStockObject(WHITE_BRUSH);
if(!RegisterClass(&wcl)) // Зарегистр. класс окна
return 0;
// Создать окно
hwnd=CreateWindow(szWinName, // Имя класса
"Работа с графикой в виртуальном окне",
WS_OVERLAPPEDWINDOW,// Стиль окна
CW_USEDEFAULT, // Х-координата
CW_USEDEFAULT, // Y-координата
CW_USEDEFAULT, // Ширина окна
CW_USEDEFAULT, // Высота окна
HWND_DESKTOP, // Нет родит. окна
NULL, // Нет меню
hThisInst, // Дескрип. приложения
NULL); // Без дополит. аргументов
// Загрузить акселераторы
hAccel=LoadAccelerators(hThisInst,"MYMENU");
ShowWindow(hwnd,nWinMode); // Показать окно и
UpdateWindow(hwnd); // перерисовать содержимое
// Запустить цикл обработки сообщений
while(GetMessage (&msg,NULL,0,0))
if(!TranslateAccelerator(hwnd,hAccel,&msg))
{
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_CREATE: // Получаем размеры экрана
maxX=GetSystemMetrics(SM_CXSCREEN);
maxY=GetSystemMetrics(SM_CYSCREEN);
hdc=GetDC(hwnd); // Совмест. с окном растр
memdc=CreateCompatibleDC(hdc);
hbit=CreateCompatibleBitmap(hdc,maxX,maxY);
SelectObject(memdc,hbit);
hbrush=(HBRUSH)GetStockObject(WHITE_BRUSH);
SelectObject(memdc,hbrush);
PatBlt(memdc,0,0,maxX,maxY,PATCOPY);
// Создать новые перья
hRedpen =CreatePen(PS_SOLID,1,RGB(255,0,0));
hGreenpen=CreatePen(PS_SOLID,1,RGB(0,255,0));
hBluepen =CreatePen(PS_SOLID,1,RGB(0,0,255));
hYellowpen=
CreatePen(PS_SOLID,1,RGB(255,255,0));
hOldpen=(HPEN)SelectObject(memdc,hRedpen);
SelectObject(memdc,hOldpen); // Старое перо
ReleaseDC(hwnd,hdc);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_LINES:
// Вывести 2 черных пикселя
SetPixel(memdc,40,14,RGB(0,0,0));
SetPixel(memdc,40,15,RGB(0,0,0));
// Вывести прямую линию
LineTo(memdc,100,50);
MoveToEx(memdc,100,50,NULL);
// Установить зеленое перо
hOldpen=
(HPEN)SelectObject(memdc,hGreenpen);
LineTo(memdc,200,100);
// Установить желтое перо
SelectObject(memdc,hYellowpen);
LineTo(memdc,0,200);
// Установить синее перо
SelectObject(memdc,hBluepen);
LineTo(memdc,200,200);
// Установить красное перо
SelectObject(memdc,hRedpen);
LineTo(memdc,0,0);
// Вернуться к прежнему перу
SelectObject (memdc, hOldpen);
// Провести дугу
Arc(memdc,0,0,300,300,0,50,200,50);
// Показать линии, отрезающие дугу
MoveToEx(memdc,150,150,NULL);
LineTo(memdc,0,50);
MoveToEx(memdc,150,150,NULL);
LineTo(memdc,200,50);
InvalidateRect(hwnd,NULL,1);
break;
case ID_RECTANGLES:
// Прямоугольники не заполняются
hOldbrush=(HBRUSH)SelectObject(memdc,
GetStockObject(HOLLOW_BRUSH));
// Рисуем прямоугольники
Rectangle(memdc,50,50,300,300);
RoundRect(memdc,125,125,220,240,15,13);
// Выбираем красное перо
SelectObject(memdc,hRedpen);
Rectangle(memdc,100,100,200,200);
SelectObject(memdc,hOldpen);
// Вернуться к прежнему перу
// Восстановить прежнюю кисть
SelectObject(memdc,hOldbrush);
InvalidateRect(hwnd,NULL,1);
break;
case ID_ELLIPSES:
// Создаем синюю кисть
hbrush=CreateSolidBrush(RGB(0,0,255));
hOldbrush=
(HBRUSH)SelectObject(memdc,hbrush);
// Рисуем эллипсы с синим заполнением
Ellipse(memdc,50,200,100,280);
Ellipse(memdc,75,25,280,100);
// Рисуем красным пером, зеленой кистью
SelectObject(memdc,hRedpen);
DeleteObject(hbrush); // Удалить кисть
// Создать зеленую кисть
hbrush=CreateSolidBrush(RGB(0,255,0));
SelectObject(memdc,hbrush);
Ellipse(memdc,100,100,200,200);
// Рисуем сектор
Pie(memdc,200,200,340,340,225,200,
200,250);
SelectObject(memdc,hOldpen);
// Вернуться к прежнему перу
SelectObject(memdc,hOldbrush);
// Восстановить прежнюю кисть и удалить
DeleteObject(hbrush); // зеленую кисть
InvalidateRect(hwnd,NULL,1);
break;
case ID_RESET:
// Восстановить текущую позицию в 0,0
MoveToEx(memdc,0,0,NULL);
// Стереть изображение при помощи
// перерисовки фона
PatBlt(memdc,0,0,maxX,maxY,PATCOPY);
InvalidateRect(hwnd,NULL,1);
break;
case ID_HELP:
MessageBox(hwnd,
"F2: линии\n"
"FЗ: прямоугольники\n"
"F4: эллипсы\n"
"F5: сброс",
"Работа с графикой",MB_OK);
break;
}
break;
case WM_PAINT: // Перерисовка окна
// Получить DC */
hdc=BeginPaint(hwnd,&paintstruct);
// Теперь копируем растр из памяти на экран
BitBlt(hdc,0,0,maxX,maxY,memdc,0,0,SRCCOPY);
// Освободить DC
EndPaint(hwnd,&paintstruct);
break;
case WM_DESTROY: // Завершение программы
// Удалить созданные перья
DeleteObject(hRedpen);
DeleteObject(hGreenpen);
DeleteObject(hBluepen);
DeleteObject(hYellowpen);
DeleteDC(memdc); // Удалить виртуальное окно
PostQuitMessage(0);
break;
default:
// Все сообщения, не обрабатываемые в данной
// функции, направляются на обработку по
// умолчанию
return DefWindowProc(hwnd,message,
wParam,lParam);
}
return 0;
}
Для этой программы потребуется следующий файл ресурсов:
#include <Windows.h>
#include "Graph.h"
MYMENU MENU
{
MENUITEM "&Линии", ID_LINES
MENUITEM "&Прямоугольники",ID_RECTANGLES
MENUITEM "&Эллипсы",ID_ELLIPSES
MENUITEM "&Cбpоc",ID_RESET
MENUITEM "Помощь",ID_HELP
}
MYMENU ACCELERATORS
{
VK_F2, ID_LINES, VIRTKEY
VK_F3, ID_RECTANGLES, VIRTKEY
VK_F4, ID_ELLIPSES, VIRTKEY
VK_F5, ID_RESET, VIRTKEY
VK_F1, ID_HELP, VIRTKEY
}
Потребуется также файл определений Graph.h:
#define ID_LINES 100
#define ID_RECTANGLES 101
#define ID_ELLIPSES 102
#define ID_RESET 103
#define ID_HELP 104
Программа создает меню, позволяющее отображать линии (и вдобавок два пикселя), прямоугольники и эллипсы. Имеется также возможность очистить окно и восстановить текущую позицию. Пример вывода различных типов графики представлен на рис. 9.2.