#include #include // Глобальные переменные const int ID_BUTTON_POLYLINE = 1001; const int ID_BUTTON_POLYGON = 1002; const int ID_BUTTON_SAVE = 1003; // Обработчик сообщений окна LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { // Регистрируем класс окна WNDCLASS wc = {}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = L"PaintApp"; RegisterClass(&wc); // Создаем окно приложения HWND hwnd = CreateWindow(L"PaintApp", L"Paint Program", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL); if (!hwnd) return -1; // Создаем кнопки CreateWindow(L"BUTTON", L"Polyline", WS_CHILD | WS_VISIBLE, 10, 10, 100, 30, hwnd, (HMENU)ID_BUTTON_POLYLINE, hInstance, NULL); CreateWindow(L"BUTTON", L"Polygon", WS_CHILD | WS_VISIBLE, 120, 10, 100, 30, hwnd, (HMENU)ID_BUTTON_POLYGON, hInstance, NULL); CreateWindow(L"BUTTON", L"Save", WS_CHILD | WS_VISIBLE, 230, 10, 100, 30, hwnd, (HMENU)ID_BUTTON_SAVE, hInstance, NULL); // Отображаем окно приложения ShowWindow(hwnd, nShowCmd); // Запускаем цикл обработки сообщений MSG msg = {}; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } // Отрисовка многоугольника void DrawPolygon(HDC hdc, const std::vector& points, COLORREF color) { HBRUSH hBrush = CreateSolidBrush(color); HPEN hPen = CreatePen(PS_SOLID, 1, color); HGDIOBJ hOldBrush = SelectObject(hdc, hBrush); HGDIOBJ hOldPen = SelectObject(hdc, hPen); Polygon(hdc, points.data(), points.size()); SelectObject(hdc, hOldBrush); SelectObject(hdc, hOldPen); DeleteObject(hBrush); DeleteObject(hPen); } // Обработчик сообщений окна LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static std::vector polyline; // Список точек ломаной static std::vector> polygons; // Список многоугольников static bool isDrawingPolyline = false; // Флаг рисования ломаной static bool isDrawingPolygon = false; // Флаг рисования многоугольника static COLORREF polylineColor = RGB(0, 0, 0); // Цвет ломаной static COLORREF polygonColor = RGB(255, 0, 0); // Цвет многоугольника switch (uMsg) { case WM_COMMAND: if (LOWORD(wParam) == ID_BUTTON_POLYLINE) // Кнопка "Polyline" { isDrawingPolyline = true; isDrawingPolygon = false; } else if (LOWORD(wParam) == ID_BUTTON_POLYGON) // Кнопка "Polygon" { isDrawingPolyline = false; isDrawingPolygon = true; } else if (LOWORD(wParam) == ID_BUTTON_SAVE) // Кнопка "Save" { // Создаем контекст для второго буфера HDC hdc = GetDC(hwnd); HDC hdcMem = CreateCompatibleDC(hdc); HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 640, 480); HGDIOBJ hOldBitmap = SelectObject(hdcMem, hBitmap); // Копируем изображение из основного буфера во второй буфер BitBlt(hdcMem, 0, 0, 640, 480, hdc, 0, 0, SRCCOPY); // Сохраняем изображение в файл OPENFILENAME ofn = {}; ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.lpstrFilter = L"BMP Files (*.bmp)\0*.bmp\0All Files (*.*)\0*.*\0"; ofn.nFilterIndex = 1; ofn.lpstrFile = new WCHAR[MAX_PATH]; ofn.lpstrFile[0] = L'\0'; ofn.nMaxFile = MAX_PATH; ofn.lpstrTitle = L"Save Image As..."; ofn.Flags = OFN_OVERWRITEPROMPT; if (GetSaveFileName(&ofn)) { HANDLE hFile = CreateFile(ofn.lpstrFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); BITMAP bmp = {}; GetObject(hBitmap, sizeof(BITMAP), &bmp); BITMAPFILEHEADER bfh = { 'MB', (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bmp.bmWidthBytes * bmp.bmHeight), 0, 0, sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) }; BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), bmp.bmWidth, bmp.bmHeight, 1, 24, BI_RGB, bmp.bmWidthBytes * bmp.bmHeight, 0, 0, 0, 0 }; DWORD bytesWritten = 0; WriteFile(hFile, &bfh, sizeof(BITMAPFILEHEADER), &bytesWritten, NULL); WriteFile(hFile, &bih, sizeof(BITMAPINFOHEADER), &bytesWritten, NULL); BYTE* pData = new BYTE[bmp.bmWidthBytes * bmp.bmHeight]; GetBitmapBits(hBitmap, bmp.bmWidthBytes * bmp.bmHeight, pData); for (int i = 0; i < bmp.bmWidthBytes * bmp.bmHeight; i += 3) { BYTE tmp = pData[i]; pData[i] = pData[i + 2]; pData[i + 2] = tmp; } WriteFile(hFile, pData, bmp.bmWidthBytes * bmp.bmHeight, &bytesWritten, NULL); CloseHandle(hFile); delete[] pData; } SelectObject(hdcMem, hOldBitmap); DeleteObject(hBitmap); DeleteDC(hdcMem); ReleaseDC(hwnd, hdc); return 0; } break; case WM_MOUSEMOVE: if (wParam & MK_LBUTTON) // Левая кнопка мыши нажата { POINT pt = { LOWORD(lParam), HIWORD(lParam) }; if (isDrawingPolyline) // Рисование ломаной { polyline.push_back(pt); HDC hdc = GetDC(hwnd); HPEN hPen = CreatePen(PS_SOLID, 1, polylineColor); HGDIOBJ hOldPen = SelectObject(hdc, hPen); if (polyline.size() >= 2) { MoveToEx(hdc, polyline[polyline.size() - 2].x, polyline[polyline.size() - 2].y, NULL); LineTo(hdc, polyline[polyline.size() - 1].x, polyline[polyline.size() - 1].y); } SelectObject(hdc, hOldPen); DeleteObject(hPen); ReleaseDC(hwnd, hdc); } } break; case WM_LBUTTONUP: if (isDrawingPolyline) // Завершение рисования ломаной { isDrawingPolyline = false; } else if (isDrawingPolygon) // Завершение рисования многоугольника { POINT pt = { LOWORD(lParam), HIWORD(lParam) }; if (polygons.empty() || (polygons.back().size() >= 2 && pt.x == polygons.back().front().x && pt.y == polygons.back().front().y)) { polygons.push_back(polyline); polyline.clear(); HDC hdc = GetDC(hwnd); DrawPolygon(hdc, polygons.back(), polygonColor); ReleaseDC(hwnd, hdc); } } break; case WM_PAINT: // Отображение сохраненных многоугольников { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); HPEN hPen = CreatePen(PS_SOLID, 1, polygonColor); HGDIOBJ hOldPen = SelectObject(hdc, hPen); for (const auto& points : polygons) { DrawPolygon(hdc, points, polygonColor); } SelectObject(hdc, hOldPen); DeleteObject(hPen); EndPaint(hwnd, &ps); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; }