Пример в этой статье иллюстрирует, как использовать функции прямоугольника. Он состоит из главной оконной процедуры приложения, которая позволяет пользователю перемещать и изменять размеры точечного рисунка.
Когда приложение стартует, оно рисует 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;
}
|