Пример в этой статье иллюстрирует, как использовать функции прямоугольника. Он состоит из главной оконной процедуры приложения, которая позволяет пользователю перемещать и изменять размеры точечного рисунка.
Когда приложение стартует, оно рисует 32 х 32 пикселя точечный рисунок в левом верхнем угле экрана. Пользователь может переместить точечный рисунок, перетаскивая его. Чтобы изменить размеры точечного рисунка, пользователь создает целевой прямоугольник, перетаскивая мышь, затем перетаскивает точечный рисунок и "вставляет" его в целевой прямоугольник. Приложение реагирует, копируя точечный рисунок в целевой прямоугольник.
Оконная процедура, которая дает возможность пользователю перемещать и изменять размеры точечного рисунка, приведена в примере ниже.
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HDC hdc; // контекст устройства (DC) окна RECT rcTmp; // временный прямоугольник PAINTSTRUCT ps; // данные о краске для функций BeginPaint и EndPaint POINT ptClientUL; // левый верхний угол клиентской области POINT ptClientLR; // клиентская область нижнего правого угла static HDC hdcCompat; // DC для копирования точечный рисунок static POINT pt; // координаты x и y курсора static RECT rcBmp; // прямоугольник, в котором заключен точечный рисунок static RECT rcTarget; // прямоугольник, который получит точечный рисунок static RECT rcClient; // клиентская область прямоугольника static BOOL fDragRect; // ИСТИНА (TRUE), если прямоугольник точечного рисунка перетащен static HBITMAP hbmp; // дескриптор точечного рисунка, который показывается (на экране) static HBRUSH hbrBkgnd; // дескриптор кисти цвета фона static COLORREF crBkgnd; // цвет фона клиентской области static HPEN hpenDot; // дескриптор пунктирного пера switch (uMsg) { case WM_CREATE: // Загрузим ресурс точечного рисунка. hbmp = LoadBitmap(hinst, MAKEINTRESOURCE(1)); // Создает контекст устройства (DC), который содержит точечный рисунок. // Точечный рисунок копируется от этого контекста устройства (DC) в контекст устройства (DC) окна // всякий раз, когда окно должно рисоваться. hdc = GetDC(hwnd); hdcCompat = CreateCompatibleDC(hdc); SelectObject(hdcCompat, hbmp); // Создаем кисть того же самого цвета, что и фон // клиентской области. Кисть используется позже, чтобы стереть // старую картинку перед копированием рисунка в // целевой прямоугольник. crBkgnd = GetBkColor(hdc); hbrBkgnd = CreateSolidBrush(crBkgnd); ReleaseDC(hwnd, hdc); // Создадим пунктирное перо. Перо используется для рисования // прямоугольника картинки, куда пользователь перетаскивает ее. hpenDot = CreatePen(PS_DOT, 1, RGB(0, 0, 0)); // Установим начальный прямоугольник для точечного рисунка. Обратите внимание! на то, что это // это приложение поддерживает только точечный рисунок // 32 на 32 пикселя. Прямоугольник немного больше, чем // точечный рисунок. SetRect(&rcBmp, 1, 1, 34, 34); return 0; case WM_PAINT: // Рисуем прямоугольник рисунка и копируем точечный рисунок в // него. Точечный рисунок 32 на 32 пикселя выровнены по центру // в прямоугольнике, добавляя 1 слева и сверху // координат растрового прямоугольника и вычитаем 2 // справа и снизу координат основания. BeginPaint(hwnd, &ps); Rectangle(ps.hdc, rcBmp.left, rcBmp.top, rcBmp.right, rcBmp.bottom); StretchBlt(ps.hdc, rcBmp.left + 1, rcBmp.top + 1, (rcBmp.right - rcBmp.left) - 2, (rcBmp.bottom - rcBmp.top) - 2, hdcCompat, 0, 0, 32, 32, SRCCOPY); EndPaint(hwnd, &ps); break; case WM_MOVE: case WM_SIZE: // Преобразуем координаты клиентской области // прямоугольника в экранные координаты и сохраним их в // прямоугольнике. Прямоугольник передается в функцию ClipCursor // в ходе обработки сообщения WM_LBUTTONDOWN. GetClientRect(hwnd, &rcClient); ptClientUL.x = rcClient.left; ptClientUL.y = rcClient.top; ptClientLR.x = rcClient.right; ptClientLR.y = rcClient.bottom; ClientToScreen(hwnd, &ptClientUL); ClientToScreen(hwnd, &ptClientLR); SetRect(&rcClient, ptClientUL.x, ptClientUL.y, ptClientLR.x, ptClientLR.y); return 0; case WM_LBUTTONDOWN: // Ограничим курсор мыши клиентской областью. Это // гарантирует то, что окно получает соответствующее // сообщение WM_LBUTTONUP. ClipCursor(&rcClient); // Сохраним координаты курсора мыши. pt.x = (LONG) LOWORD(lParam); pt.y = (LONG) HIWORD(lParam); // Если пользователь сделал щелчок мышью по прямоугольнику рисунка, то он перерисует // его используя пунктирное перо. Установите флажок fDragRect, чтобы // сообщить, что пользователь собирается перетащить прямоугольник. if (PtInRect(&rcBmp, pt)) { hdc = GetDC(hwnd); SelectObject(hdc, hpenDot); Rectangle(hdc, rcBmp.left, rcBmp.top, rcBmp.right, rcBmp.bottom); fDragRect = TRUE; ReleaseDC(hwnd, hdc); } return 0; case WM_MOUSEMOVE: // Нарисуем целевой прямоугольник или перетащим прямоугольник рисунка, // в зависимости от состояния флажка fDragRect. if ((wParam && MK_LBUTTON) && !fDragRect) { // Установим режим смешивания так, чтобы цвет пера был // инверсия цвета фона. Предыдущий // прямоугольник может затем быть стерт, рисунком // другого прямоугольника поверх прежнего. hdc = GetDC(hwnd); SetROP2(hdc, R2_NOTXORPEN); // Если предыдущий целевой прямоугольник существует, то сотрем // его рисуя другой прямоугольник поверх прежнего. if (!IsRectEmpty(&rcTarget)) { Rectangle(hdc, rcTarget.left, rcTarget.top, rcTarget.right, rcTarget.bottom); } // Сохраним координаты целевого прямоугольника. Чтобы избежать // недопустимых прямоугольников, обеспечим, чтобы значение // левой координаты было больше, чем значение // правая координата, и что значение координат // основания больше, чем координата вершины. if ((pt.x < (LONG) LOWORD(lParam)) && (pt.y > (LONG) HIWORD(lParam))) { SetRect(&rcTarget, pt.x, HIWORD(lParam), LOWORD(lParam), pt.y); } else if ((pt.x > (LONG) LOWORD(lParam)) && (pt.y > (LONG) HIWORD(lParam))) { SetRect(&rcTarget, LOWORD(lParam), HIWORD(lParam), pt.x, pt.y); } else if ((pt.x > (LONG) LOWORD(lParam)) && (pt.y < (LONG) HIWORD(lParam))) { SetRect(&rcTarget, LOWORD(lParam), pt.y, pt.x, HIWORD(lParam)); } else { SetRect(&rcTarget, pt.x, pt.y, LOWORD(lParam), HIWORD(lParam)); } // Рисуем новый целевой прямоугольник. Rectangle(hdc, rcTarget.left, rcTarget.top, rcTarget.right, rcTarget.bottom); ReleaseDC(hwnd, hdc); } else if ((wParam && MK_LBUTTON) && fDragRect) { // Установим режим смешивания так, чтобы цвет пера был // инверсией цвета фона. hdc = GetDC(hwnd); SetROP2(hdc, R2_NOTXORPEN); // Выберем пунктирное перо в контекст устройства (DC) и сотрем // предыдущий прямоугольник рисунка, рисуя // другой прямоугольник поверх прежнего. SelectObject(hdc, hpenDot); Rectangle(hdc, rcBmp.left, rcBmp.top, rcBmp.right, rcBmp.bottom); // Установите новые координаты прямоугольника рисунка, // затем перерисуйте его. OffsetRect(&rcBmp, LOWORD(lParam) - pt.x, HIWORD(lParam) - pt.y); Rectangle(hdc, rcBmp.left, rcBmp.top, rcBmp.right, rcBmp.bottom); ReleaseDC(hwnd, hdc); // Сохраним координаты курсора мыши. pt.x = (LONG) LOWORD(lParam); pt.y = (LONG) HIWORD(lParam); } return 0; case WM_LBUTTONUP: // Если прямоугольник рисунка и целевой прямоугольник // частично совпадают, скопируем точечный рисунок в целевой // прямоугольник. В противном случае, скопируем точечный рисунок в // прямоугольник точечного рисунка в его новом местоположении. if (IntersectRect(&rcTmp, &rcBmp, &rcTarget)) { // Сотрем прямоугольник рисунка, заполняя его // цветом фона. hdc = GetDC(hwnd); FillRect(hdc, &rcBmp, hbrBkgnd); // Перерисуем целевой прямоугольник, потому что часть // его пересеклась с прямоугольником рисунка, который был // стерт вызовом в FillRect. Rectangle(hdc, rcTarget.left, rcTarget.top, rcTarget.right, rcTarget.bottom); // Скопируем точечный рисунок в целевой прямоугольник. StretchBlt(hdc, rcTarget.left + 1, rcTarget.top + 1, (rcTarget.right - rcTarget.left) - 2, (rcTarget.bottom - rcTarget.top) - 2, hdcCompat, 0, 0, 32, 32, SRCCOPY); // Скопируем целевой прямоугольник в прямоугольник // точечного рисунка, установим координаты целевого // прямоугольника в 0, затем возвратим в исходное положение флажок fDragRect. CopyRect(&rcBmp, &rcTarget); SetRectEmpty(&rcTarget); ReleaseDC(hwnd, hdc); fDragRect = FALSE; } else if (fDragRect) { // Нарисуем прямоугольник рисунка, скопируем точечный рисунок в // него, и возвратим в исходное положение флажок fDragRect. hdc = GetDC(hwnd); Rectangle(hdc, rcBmp.left, rcBmp.top, rcBmp.right, rcBmp.bottom); StretchBlt(hdc, rcBmp.left + 1, rcBmp.top + 1, (rcBmp.right - rcBmp.left) - 2, (rcBmp.bottom - rcBmp.top) - 2, hdcCompat, 0, 0, 32, 32, SRCCOPY); ReleaseDC(hwnd, hdc); fDragRect = FALSE; } // Освободим курсор мыши. ClipCursor((LPRECT) NULL); return 0; case WM_DESTROY: // Уничтожим фоновую кисть, совместимый точечный рисунок, // и точечный рисунок. DeleteObject(hbrBkgnd); DeleteDC(hdcCompat); DeleteObject(hbmp); PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return (LRESULT) NULL; } |