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 добавьте код, который изображает фигуры.
¨ В ветви обработки мышиных событий добавьте код, который позволяет перемещать фигуры, добавлять новые и удалять выбранные пользователем фигуры.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.