Графический интерфейс GDI в Microsoft Windows© Александр Фролов, Григорий ФроловТом 4, М.: Диалог-МИФИ, 1993, 288 стр. 2.4. Приложение LINERДля демонстрации функций рисования графических изображений в различных режимах фона и с использованием различных растровых операций мы подготовили приложение LINER. Кроме всего прочего, в этом приложении мы получаем контекст отображения, пригодный для рисования во всем окне, в частности, в области заголовка окна (рис. 2.23).
Рис. 2.23. Приложение LINER Меню "Draw" предназначено для выбора фигур, отображаемых в окне приложения. Вы можете выбрать прямые линии (строка "Lines"), ломаную линию (строка "Polyline"), дугу эллипса ("Arc"), прямоугольники ("Rectangles"), многоугольники ("Polygon"), эллипс ("Ellipse"), окружность ("Circle"), сегмент эллипса ("Chord") или сектор эллипса ("Pie"). Запустите приложение LINER (готовый загрузочный модуль и исходные тексты приложения есть на дискете, которую можно купить вместе с книгой) и выберите из меню "Draw" строку "Rectangles". В главном окне будет нарисовано несколько прямоугольников, в том числе один прямоугольник будет нарисован по периметру внутренней области окна. По умолчанию сразу после запуска приложения используется режим фона OPAQUE. Смените его на TRANSPARENT, выбрав соответствующую строку из меню "Background Mode". Режим фона изменится на прозрачный (рис. 2.24).
Рис. 2.24. Прозрачный режим фона Посмотрите, как отражается изменение фона на рисовании других фигур, например, прямых линий (рис. 2.25).
Рис. 2.25. Рисование прямых линий различной толщины и стиля Меню "ROP" позволит вам провести эксперименты с различными растровыми операциями. Выбрав из меню "Draw" строку "Polygon", вы сможете посмотреть, как закрашиваются самопересекающиеся многоугольники в режимах ALTERNATE и WINDING (рис. 2.26).
Рис. 2.26. Режимы закрашивания многоугольников Главный файл приложения LINER приведен в листинге 2.1. Листинг 2.1. Файл liner/liner.cpp // ---------------------------------------- // Приложение LINER // Демонстрация использования функций // рисования графических изображений // ---------------------------------------- #define STRICT #include <windows.h> #include <windowsx.h> #include <mem.h> #pragma hdrstop #include "liner.hpp" // Прототипы функций BOOL InitApp(HINSTANCE); LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM); void DrawLines(HDC); void DrawPolyline(HDC); void DrawArc(HDC); void DrawRectangles(HDC); void DrawPolygon(HDC); void DrawEllipse(HDC); void DrawCircle(HDC); void DrawPie(HDC); void DrawChord(HDC); // Имя класса окна char const szClassName[] = "LinerClass"; // Заголовок окна char const szWindowTitle[] = "Liner"; // Размеры внутренней области окна short cxClient, cyClient; // Код выбранной строки меню "Draw" int nFigures = 0; // Режим фона int nBkMode = OPAQUE; // Код растровой операции int nROP2 = R2_COPYPEN; // ===================================== // Функция WinMain // ===================================== #pragma argsused int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; // структура для работы с сообщениями HWND hwnd; // идентификатор главного окна приложения // Инициализируем приложение if(!InitApp(hInstance)) return FALSE; // После успешной инициализации приложения создаем // главное окно приложения hwnd = CreateWindow( szClassName, // имя класса окна szWindowTitle, // заголовок окна WS_OVERLAPPEDWINDOW, // стиль окна CW_USEDEFAULT, // задаем размеры и расположение CW_USEDEFAULT, // окна, принятые по умолчанию CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, NULL); // Если создать окно не удалось, завершаем приложение if(!hwnd) return FALSE; // Рисуем главное окно ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); // Запускаем цикл обработки сообщений while(GetMessage(&msg, 0, 0, 0)) { DispatchMessage(&msg); } return msg.wParam; } // ===================================== // Функция InitApp // Выполняет регистрацию класса окна // ===================================== BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации // класса окна // Записываем во все поля структуры нулевые значения memset(&wc, 0, sizeof(wc)); // Подключаем меню wc.lpszMenuName = "APP_MENU"; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) WndProc; 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(LTGRAY_BRUSH); wc.lpszClassName = (LPSTR)szClassName; // Регистрация класса aWndClass = RegisterClass(&wc); return (aWndClass != 0); } // ===================================== // Функция WndProc // ===================================== LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; switch (msg) { // При изменении размеров окна сохраняем // новые значения для ширины и высоты case WM_SIZE: { cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0; } // Рисование в окне case WM_PAINT: { HBRUSH hbrush, hbrushOldBrush; int nCapHeight, nFrameHeight; // Рисуем в области заголовка окна // Получаем контекст отображения для // всего окна hdc = GetWindowDC(hwnd); // Определяем высоту заголовка окна nCapHeight = GetSystemMetrics(SM_CYCAPTION); // Определяем толщину рамки окна nFrameHeight = GetSystemMetrics(SM_CYFRAME); // Создаем кисть зеленого цвета hbrush = CreateSolidBrush(RGB(0,0xff,0)); // Выбираем кисть в контекст отображения, сохраняя // идентификатор старой кисти hbrushOldBrush = SelectBrush(hdc, hbrush); // Рисуем зеленый прямоугольник в левой части // заголовка окна Rectangle(hdc, 2*nCapHeight, nFrameHeight, 4*nCapHeight, nCapHeight); // Создаем и выбираем зеленую кисть hbrush = CreateSolidBrush(RGB(0xff,0,0)); SelectBrush(hdc, hbrush); // Вписываем в прямоугольник эллипс // красного цвета Ellipse(hdc, 2*nCapHeight, nFrameHeight, 4*nCapHeight, nCapHeight); // Выбираем старую кисть SelectBrush(hdc, hbrushOldBrush); // Освобождаем контекст отображения, // позволяющий рисовать во всем окне ReleaseDC(hwnd, hdc); // Рисуем во внутренней области окна // Получаем контекст отображения для // рисования во внутренней области окна hdc = BeginPaint(hwnd, &ps); // Устанавливаем метрическую систему // координат с началом координат в // левом нижнем углу внутренней области // окна SetMapMode(hdc, MM_LOMETRIC); SetViewportOrg(hdc, 0, cyClient); // Устанавливаем режим отображения и // растровую операцию SetBkMode(hdc, nBkMode); SetROP2(hdc, nROP2); // В зависимости от содержимого переменной // nFigures вызываем одну из функций рисования if(nFigures == CM_LINES) { DrawLines(hdc); // прямые линии } else if(nFigures == CM_ARC) { DrawArc(hdc); // дуга окружности } else if(nFigures == CM_RECT) { DrawRectangles(hdc); // прямоугольники } else if(nFigures == CM_POLYGON) { DrawPolygon(hdc); // многоугольники } else if(nFigures == CM_ELLIPSE) { DrawEllipse(hdc); // эллипс } else if(nFigures == CM_CIRCLE) { DrawCircle(hdc); // окружность } else if(nFigures == CM_PIE) { DrawPie(hdc); // сектор эллипса } else if(nFigures == CM_CHORD) { DrawChord(hdc); // сегмент эллипса } else if(nFigures == CM_POLYLINE) { DrawPolyline(hdc); // ломаная линия } // Освобождаем контекст отображения EndPaint(hwnd, &ps); return 0; } // Обработка сообщений от меню case WM_COMMAND: { switch (wParam) { case CM_HELPABOUT: { MessageBox(hwnd, "Liner, v.1.0\n" "Drawing Graphics Demo\n" "(C) Frolov A.V., 1994", "About Liner", MB_OK | MB_ICONINFORMATION); return 0; } // Режим непрозрачного фона case CM_OPAQUE: { // Записываем код режима nBkMode = OPAQUE; // Перерисовываем окно приложения InvalidateRect(hwnd, NULL, TRUE); return 0; } // Режим прозрачного фона case CM_TRANSPARENT: { nBkMode = TRANSPARENT; InvalidateRect(hwnd, NULL, TRUE); return 0; } // Выбор растровой операции case CM_R2_BLACK: { // Записываем код растровой операции nROP2 = R2_BLACK; // Перерисовываем окно приложения InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOTMERGEPEN: { nROP2 = R2_NOTMERGEPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MASKNOTPEN: { nROP2 = R2_MASKNOTPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOTCOPYPEN: { nROP2 = R2_NOTCOPYPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MASKPENNOT: { nROP2 = R2_MASKPENNOT; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOT: { nROP2 = R2_NOT; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_XORPEN: { nROP2 = R2_XORPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOTMASKPEN: { nROP2 = R2_NOTMASKPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MASKPEN: { nROP2 = R2_MASKPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOTXORPEN: { nROP2 = R2_NOTXORPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_NOP: { nROP2 = R2_NOP; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MERGENOTPEN: { nROP2 = R2_MERGENOTPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_COPYPEN: { nROP2 = R2_COPYPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MERGEPENNOT: { nROP2 = R2_MERGEPENNOT; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_MERGEPEN: { nROP2 = R2_MERGEPEN; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_R2_WHITE: { nROP2 = R2_WHITE; InvalidateRect(hwnd, NULL, TRUE); return 0; } // Выбор из меню "Draw" case CM_LINES: { nFigures = CM_LINES; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_POLYLINE: { nFigures = CM_POLYLINE; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_ARC: { nFigures = CM_ARC; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_RECT: { nFigures = CM_RECT; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_POLYGON: { nFigures = CM_POLYGON; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_ELLIPSE: { nFigures = CM_ELLIPSE; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_CIRCLE: { nFigures = CM_CIRCLE; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_PIE: { nFigures = CM_PIE; InvalidateRect(hwnd, NULL, TRUE); return 0; } case CM_CHORD: { nFigures = CM_CHORD; InvalidateRect(hwnd, NULL, TRUE); return 0; } // Завершаем работу приложения case CM_FILEEXIT: { DestroyWindow(hwnd); return 0; } default: return 0; } } case WM_DESTROY: { PostQuitMessage(0); return 0; } default: break; } return DefWindowProc(hwnd, msg, wParam, lParam); } Исходные тексты обильно снабжены комментариями, поэтому мы сделаем только самые необходимые пояснения. При регистрации класса окна указываются стили CS_HREDRAW и CS_VREDRAW, в результате чего окно перерисовывается при изменении его высоты или ширины: wc.style = CS_HREDRAW | CS_VREDRAW; Функция окна содержит обработчик сообщения WM_SIZE, который сохраняет размеры внутренней области окна в глобальных переменных cxClient и cyClient. Обработчик сообщения WM_PAINT два раза получает контекст отображения. Вначале он получает контекст отображения, позволяющий рисовать во всем окне приложения: hdc = GetWindowDC(hwnd); Используя этот контекст отображения, обработчик сообщения WM_PAINT рисует в области заголовка окна эллипс, вписанный в прямоугольник. После этого указанный контекст отображения освобождается: ReleaseDC(hwnd, hdc); Далее обработчик сообщения WM_PAINT получает общий контекст отображения, связанный с внутренней областью окна, вызывая функцию BeginPaint. В этом контексте отображения устанавливается метрический режим отображения, причем в качестве единицы длины используется одна десятая миллиметра. Начало осей координат сдвигается в левый нижний угол: SetMapMode(hdc, MM_LOMETRIC); SetViewportOrg(hdc, 0, cyClient); Далее в соответствии с содержимым глобальной переменной nBkMode устанавливается режим фона: SetBkMode(hdc, nBkMode); Первоначально в этой переменной находится значение OPAQUE. Вы можете изменить содержимое переменной nBkMode с помощью меню "Background Mode" на TRANSPARENT. Аналогично устанавливается растровая операция, используемая для рисования: SetROP2(hdc, nROP2); Далее обработчик сообщения WM_PAINT анализирует содержимое переменной nFigures, которое сразу после запуска приложения равно 0. Когда вы выбираете строку из меню "Draw", в эту переменную записывается идентификатор выбранной из меню строки. При обработке сообщения WM_PAINT в зависимости от содержимого переменной вызывается одна из нескольких функций, рисующих различные фигуры. Исходные тексты этих функций вынесены в отдельный файл (листинг 2.2). Перед возвратом управления контекст отображения освобождается функцией EndPaint. Обработчик сообщения WM_COMMAND предназначен для меню. После каждого изменения режима или кода растровой операции вызывается функция InvalidateRect, в результате чего в очередь сообщений записывается сообщение WM_PAINT: case CM_TRANSPARENT: { nBkMode = TRANSPARENT; InvalidateRect(hwnd, NULL, TRUE); return 0; } Функции, рисующие изображения, мы вынесли в отдельный файл (листинг 2.2). Листинг 2.2. Файл liner/drawfn.cpp // ---------------------------------------- // Функции для приложения LINER // ---------------------------------------- #define STRICT #include <windows.h> #include <windowsx.h> #include <mem.h> #include "liner.hpp" // Прототипы функций void DrawLines(HDC); void DrawPolyline(HDC); void DrawArc(HDC); void DrawRectangles(HDC); void DrawPolygon(HDC); void DrawEllipse(HDC); void DrawCircle(HDC); void DrawPie(HDC); void DrawChord(HDC); // Размеры внутренней области окна extern short cxClient, cyClient; // ------------------------------------------- // DrawLines // Рисование линий различной толщины и стиля // ------------------------------------------- void DrawLines(HDC hdc) { HPEN hpenW10, hpenW50; HPEN hpenDot, hpenDash, hpenDashDot, hpenOldPen; // Создаем несколько перьев: два пера толщиной // 1 мм и 5 мм, пунктирное, штриховое и // штрих-пунктирное hpenW10 = CreatePen(PS_SOLID, 10, RGB(0,0,0)); hpenW50 = CreatePen(PS_SOLID, 50, RGB(0,0,0)); hpenDot = CreatePen(PS_DOT, 0, RGB(0,0,0)); hpenDash = CreatePen(PS_DASH, 0, RGB(0,0,0)); hpenDashDot = CreatePen(PS_DASHDOT, 0, RGB(0,0,0)); // Рисуем тонкую линию пером, выбранным в контекст // отображения по умолчанию, и подписываем эту линию MoveToEx(hdc, 100, 100, NULL); LineTo(hdc, 600, 100); TextOut(hdc, 700, 100, "PS_SOLID, 1 pixel", 17); // Выбираем перо толщиной 1 мм hpenOldPen = SelectPen(hdc, hpenW10); // Рисуем линию выбранным пером MoveToEx(hdc, 100, 200, NULL); LineTo(hdc, 600, 200); TextOut(hdc, 700, 200, "PS_SOLID, 1 mm", 14); // Перебираем остальные перья SelectPen(hdc, hpenW50); MoveToEx(hdc, 100, 300, NULL); LineTo(hdc, 600, 300); TextOut(hdc, 700, 300, "PS_SOLID, 5 mm", 14); SelectPen(hdc, hpenDot); MoveToEx(hdc, 100, 400, NULL); LineTo(hdc, 600, 400); TextOut(hdc, 700, 400, "PS_DOT", 6); SelectPen(hdc, hpenDash); MoveToEx(hdc, 100, 500, NULL); LineTo(hdc, 600, 500); TextOut(hdc, 700, 500, "PS_DASH", 7); SelectPen(hdc, hpenDashDot); MoveToEx(hdc, 100, 600, NULL); LineTo(hdc, 600, 600); TextOut(hdc, 700, 600, "PS_DASHDOT", 10); // Выбираем старое перо SelectPen(hdc, hpenOldPen); // Удаляем созданные нами перья DeletePen(hpenW10); DeletePen(hpenW50); DeletePen(hpenDot); DeletePen(hpenDash); DeletePen(hpenDashDot); } // ------------------------------------------- // DrawPolyline // Рисование ломаной линии // ------------------------------------------- void DrawPolyline(HDC hdc) { // Массив координат точек излома POINT ptPoints[] = { {10, 10}, {100, 310}, {40, 300}, {300, 15}, {135, 340}, {113, 125}, {250, 137}, {300, 300} }; // Рисуем ломаную линию Polyline(hdc, ptPoints, sizeof ptPoints / sizeof ptPoints[0]); } // ------------------------------------------- // DrawArc // Рисование дуги эллипса // ------------------------------------------- void DrawArc(HDC hdc) { HPEN hpenW10, hpenOldPen; // Создаем перо толщиной 1 мм и выбираем его hpenW10 = CreatePen(PS_SOLID, 10, RGB(0,0,0)); hpenOldPen = SelectPen(hdc, hpenW10); // Рисуем дугу Arc(hdc, 100, 600, // верхний левый угол прямоугольника 800, 100, // нижний правый угол прямоугольника 650, 650, // начало 750, 0); // конец // Выбираем старое перо SelectPen(hdc, hpenOldPen); // Удаляем созданное перо DeletePen(hpenW10); } // ------------------------------------------- // DrawRectangles // Рисование прямоугольников // ------------------------------------------- void DrawRectangles(HDC hdc) { HPEN hpenW10, hpenOldPen; HBRUSH hbrush, hbrushOldBrush; POINT pt[2]; RECT rc = {350, 500, 500, 400}; // Рисуем прямоугольник вокруг внутренней области окна // Так как установлен метрический режим отображения, // а размеры окна, передаваемые вместе с сообщением // WM_SIZE, выражены в пикселах, выполняем // преобразование физических координат в логические pt[0].x = 0; pt[0].y = cyClient; pt[1].x = cxClient; pt[1].y = 0; DPtoLP(hdc, pt, 2); // Создаем перо толщиной 1 мм и выбираем его hpenW10 = CreatePen(PS_SOLID, 10, RGB(0,0,0)); hpenOldPen = SelectPen(hdc, hpenW10); // Рисуем прямоугольник Rectangle(hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y); // Выбираем серую кисть hbrush = GetStockBrush(GRAY_BRUSH); hbrushOldBrush = SelectBrush(hdc, hbrush); // Рисуем прямоугольник, закрашенный серым цветом Rectangle(hdc, 100, 500, 300, 50); // Создаем и выбираем кисть для штриховки hbrush = CreateHatchBrush(HS_DIAGCROSS, RGB(0,0,0)); SelectBrush(hdc, hbrush); // Рисуем заштрихованный прямоугольник Rectangle(hdc, 50, 300, 500, 100); // Выбираем старое перо и кисть SelectPen(hdc, hpenOldPen); SelectBrush(hdc, hbrushOldBrush); // Заштриховываем прямоугольную область кистью // hbrush, которая НЕ ВЫБРАНА в контекст FillRect(hdc, &rc, hbrush); // Рисуем прямоугольник со скругленными углами RoundRect(hdc, 550, 200, 800, 100, 50, 50); // Удаляем созданные нами перо и кисть DeletePen(hpenW10); DeleteBrush(hbrush);} // ------------------------------------------- // DrawPolygon // Рисование многоугольника // ------------------------------------------- void DrawPolygon(HDC hdc) { HBRUSH hbrush, hbrushOldBrush; int nOldPolyFillMode; // Координаты вершин первого многоугольника POINT ptPoints1[] = { {10, 10}, {100, 310}, {40, 300}, {300, 15}, {135, 340}, {113, 125}, {250, 137}, {300, 300} }; // Координаты вершин второго многоугольника POINT ptPoints2[] = { {310, 10}, {400, 310}, {340, 300}, {600, 15}, {435, 340}, {413, 125}, {550, 137}, {600, 300} }; // Выбираем встроенную серую кисть hbrush = GetStockBrush(GRAY_BRUSH); hbrushOldBrush = SelectBrush(hdc, hbrush); // Рисуем первый многоугольник в режиме // заполнения ALTERNATE, установленном // по умолчанию Polygon(hdc, ptPoints1, sizeof ptPoints1 / sizeof ptPoints1[0]); // Устанавливаем режим заполнения WINDING nOldPolyFillMode = SetPolyFillMode(hdc, WINDING); // Рисуем второй многоугольник Polygon(hdc, ptPoints2, sizeof ptPoints2 / sizeof ptPoints2[0]); // Восстанавливаем старый режим заполнения SetPolyFillMode(hdc, nOldPolyFillMode); SelectBrush(hdc, hbrushOldBrush); } // ------------------------------------------- // DrawEllipse // Рисование эллипса // ------------------------------------------- void DrawEllipse(HDC hdc) { POINT pt[2]; // Эллипс будет вписан во внутреннюю область // окна, поэтому определяем координаты углов // в текущей (метрической) системе координат, // выполняя преобразование pt[0].x = 0; pt[0].y = cyClient; pt[1].x = cxClient; pt[1].y = 0; DPtoLP(hdc, pt, 2); // Рисуем эллипс Ellipse(hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y); } // ------------------------------------------- // DrawCircle // Рисование окружности // ------------------------------------------- void DrawCircle(HDC hdc) { // Рисуем эллипс, вписанный в квадрат Ellipse(hdc, 100, 600, 600, 100); } // ------------------------------------------- // DrawPie // Рисование сектора круга // ------------------------------------------- void DrawPie(HDC hdc) { HPEN hpenW10, hpenOldPen; // Создаем перо и выбираем его hpenW10 = CreatePen(PS_SOLID, 10, RGB(0,0,0)); hpenOldPen = SelectPen(hdc, hpenW10); // Рисуем сектор круга Pie(hdc, 100, 600, 800, 100, 650, 650, 750, 0); // Выбираем старое перо и удаляем созданное SelectPen(hdc, hpenOldPen); DeletePen(hpenW10); } // ------------------------------------------- // DrawChord // Рисование сегмента круга // ------------------------------------------- void DrawChord(HDC hdc) { HPEN hpenW10, hpenOldPen; hpenW10 = CreatePen(PS_SOLID, 10, RGB(0,0,0)); hpenOldPen = SelectPen(hdc, hpenW10); // Рисуем сегмент круга Chord(hdc, 100, 600, 800, 100, 650, 650, 750, 0); SelectPen(hdc, hpenOldPen); DeletePen(hpenW10); } Символические имена констант, используемые для идентификации строк меню, описаны в файле liner.hpp (листинг 2.3). Листинг 2.3. Файл liner/liner.hpp #define CM_HELPABOUT 301 #define CM_OPAQUE 302 #define CM_TRANSPARENT 303 #define CM_FILEEXIT 304 #define CM_POLYGON 305 #define CM_PIE 306 #define CM_CHORD 307 #define CM_ELLIPSE 308 #define CM_RECT 309 #define CM_ARC 310 #define CM_LINES 311 #define CM_POLYLINE 312 #define CM_CIRCLE 313 #define CM_R2_BLACK 201 #define CM_R2_NOTMERGEPEN 202 #define CM_R2_MASKNOTPEN 203 #define CM_R2_NOTCOPYPEN 204 #define CM_R2_MASKPENNOT 205 #define CM_R2_NOT 206 #define CM_R2_XORPEN 207 #define CM_R2_NOTMASKPEN 208 #define CM_R2_MASKPEN 209 #define CM_R2_NOTXORPEN 210 #define CM_R2_NOP 211 #define CM_R2_MERGENOTPEN 212 #define CM_R2_COPYPEN 213 #define CM_R2_MERGEPENNOT 214 #define CM_R2_MERGEPEN 215 #define CM_R2_WHITE 216 Меню приложения определено в файле ресурсов liner.rc (листинг 2.4). Листинг 2.4. Файл liner/liner.rc #include "liner.hpp" APP_MENU MENU BEGIN POPUP "&File" BEGIN MENUITEM "E&xit", CM_FILEEXIT END POPUP "&Draw" BEGIN MENUITEM "&Lines", CM_LINES MENUITEM "&Polyline", CM_POLYLINE MENUITEM "&Arc", CM_ARC MENUITEM "&Rectangles", CM_RECT MENUITEM "P&opygon", CM_POLYGON MENUITEM "&Ellipse", CM_ELLIPSE MENUITEM "C&ircle", CM_CIRCLE MENUITEM "&Chord", CM_CHORD MENUITEM "&Pie", CM_PIE END POPUP "&Background Mode" BEGIN MENUITEM "&Opaque", CM_OPAQUE MENUITEM "&Transparent", CM_TRANSPARENT END POPUP "&ROP" BEGIN MENUITEM "R2_BLACK", CM_R2_BLACK MENUITEM "R2_NOTMERGEPEN", CM_R2_NOTMERGEPEN MENUITEM "R2_MASKNOTPEN", CM_R2_MASKNOTPEN MENUITEM "R2_NOTCOPYPEN", CM_R2_NOTCOPYPEN MENUITEM "R2_MASKPENNOT", CM_R2_MASKPENNOT MENUITEM "R2_NOT", CM_R2_NOT MENUITEM "R2_XORPEN", CM_R2_XORPEN MENUITEM "R2_NOTMASKPEN", CM_R2_NOTMASKPEN MENUITEM "R2_MASKPEN", CM_R2_MASKPEN MENUITEM "R2_NOTXORPEN", CM_R2_NOTXORPEN MENUITEM "R2_NOP", CM_R2_NOP MENUITEM "R2_MERGENOTPEN", CM_R2_MERGENOTPEN MENUITEM "R2_COPYPEN", CM_R2_COPYPEN MENUITEM "R2_MERGEPENNOT", CM_R2_MERGEPENNOT MENUITEM "R2_MERGEPEN", CM_R2_MERGEPEN MENUITEM "R2_WHITE", CM_R2_WHITE END POPUP "&Help" BEGIN MENUITEM "&About...", CM_HELPABOUT END END Файл liner.def используется для определения модуля приложения LINER (листинг 2.5). Листинг 2.5. Файл liner/liner.def ; ============================= ; Файл определения модуля ; ============================= NAME LINER DESCRIPTION 'Приложение LINER, (C) 1994, Frolov A.V.' EXETYPE windows STUB 'winstub.exe' STACKSIZE 8120 HEAPSIZE 1024 CODE preload moveable discardable DATA preload moveable multiple |