Использование прямоугольников


Пример в этой статье иллюстрирует, как использовать функции прямоугольника. Он состоит из главной оконной процедуры приложения, которая позволяет пользователю перемещать и изменять размеры точечного рисунка.

Когда приложение стартует, оно рисует 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;
}
 
Назад в оглавление
На главную страницу

Hosted by uCoz