Управление растровым изображением. Альтернативные способы перерисовки динамического прямоугольника. Работа с растровыми изображениями, страница 11

if (!(wParam & MK_LBUTTON))

return 0;

short x = LOWORD(lParam),  y = HIWORD(lParam);

if (bDrag) // Перемещение изображения

{

OffsetRect (&rBmp, x - ptOld.x, y - ptOld.y);

ptOld.x = x; ptOld.y = y;

InvalidateRect(hWnd, 0, FALSE);

}

else   // Динамический прямоугольник

{

hdc = GetDC(hWnd);

if (!IsRectEmpty (&rTarget))

DrawFocusRect (hdc, &rTarget);

SetRect (&rTarget, ptOld.x, ptOld.y, x, y);

if (ptOld.x > x)

{

rTarget.left = x;

rTarget.right = ptOld.x;

}

if (ptOld.y > y)

{

rTarget.top = y;

rTarget.bottom = ptOld.y;

}

DrawFocusRect(hdc, &rTarget);

ReleaseDC(hWnd, hdc);

}

break;

}

case WM_LBUTTONUP:

ClipCursor (0); 

bDrag = false;

if (IntersectRect (&rTmp, &rBmp, &rTarget))

{

CopyRect(&rBmp, &rTarget);

InvalidateRect(hWnd, 0, TRUE);

SetRectEmpty(&rTarget);

}

break;

case WM_DESTROY:

DeleteObject (hbrBkgnd);

DeleteDC (hMemDC);

DeleteDC (hdcClient);

PostQuitMessage(0);

break;

case WM_MOVE:

case WM_SIZE:       // Узнаем и преобразовываем координаты клиентской области окна

{

GetClientRect(hWnd, &rClient);

POINT ptLT = { rClient.left, rClient.top };

POINT ptRB = { rClient.right, rClient.bottom };

ClientToScreen(hWnd, &ptLT);

ClientToScreen(hWnd, &ptRB);

SetRect (&rClient, ptLT.x, ptLT.y, ptRB.x, ptRB.y);

szClient.cx = rClient.right - rClient.left;

szClient.cy = rClient.bottom - rClient.top;

SetRectEmpty (&rTarget);

break;

}

default:

return DefWindowProc(hWnd,msg,wParam,lParam);

}

return 0L;

}

¨  Запустите и проверьте качество перерисовки всех компонентов. Теперь вы знаете, как работает технология flicker-free drawing.

Задание

1.  Подключите к проекту новый файл Step06.cpp и отключите старый.

2.  Введите в файл код, приведенный ниже.

3.  Добавьте возможность плавного перетаскивания двух объектов, использующих градиентные кисти.

LRESULT WINAPI WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

switch(msg)

{

case WM_PAINT:

{

PAINTSTRUCT ps;

HDC hdc = BeginPaint(hWnd, &ps);

TRIVERTEX vert[2] =

{

{ 20, 20,  0xff00, 0, 0, 0 },

{ 300,300, 0, 0, 0xff00, 0 },

};

GRADIENT_RECT rect;

rect.UpperLeft  = 0;

rect.LowerRight = 1;

GradientFill (hdc, vert, 2, &rect, 1, GRADIENT_FILL_RECT_H);

TRIVERTEX v [4] =

{

{ 400, 20,  0xff00, 0xff00, 0, 0 },

{ 700, 20,  0, 0xff00, 0xff00, 0 },

{ 700, 200, 0, 0, 0xff00, 0 },

{ 400, 200, 0xff00, 0xff00, 0xff00, 0 },

};

GRADIENT_TRIANGLE tria[2] =

{

{ 0, 1, 2 },

{ 0, 2, 3 }

};

GradientFill (hdc, v, 4, &tria, 1, GRADIENT_FILL_TRIANGLE);

EndPaint(hWnd, &ps);

break;

}

case WM_DESTROY: PostQuitMessage(0); break;

default:      

return DefWindowProc(hWnd,msg,wParam,lParam);

}

return 0L;

}

¨  Разработайте класс Shape, который содержит массив вершин типа TREEVERTEX и методы: Draw, PtInShape и Move. Первые два должны быть чисто виртуальными, третий — нет.

¨  Разработайте два класса, производных от Shape: ShapeTria и ShapeRect. Первый должен изображать градиентный треугольник, а второй — градиентный прямоугольник. Реализуйте виртуальные методы.

¨  Разработайте класс Shapes, который содержит динамическую коллекцию vector<Shape*> shapes; и коллекцию новых точек вида vector<POINT> points;. Класс также должен иметь методы: AddPoint, AddShape, DeleteShape, GetActive.

¨  В оконную процедуру добавьте две переменные.

static Shapes figures;

static Shape* dragged;

¨  В ветвь обработки события WM_CREATE добавьте код, который наполняет коллекцию figures.

figures.AddShape(new ShapeTria(tria, 3));

figures.AddShape(new ShapeRect(rect, 2));

¨  В ветвь обработки события WM_PAINT добавьте код, который изображает фигуры.

¨  В ветви обработки мышиных событий добавьте код, который позволяет перемещать фигуры, добавлять новые и удалять выбранные пользователем фигуры.