简单就是:在图形范围内判断鼠标点击,捕获鼠标,随着鼠标的移动,不断地擦除原有位置上的图形,在新位置上绘图。
要保存好:图形位置
(
左上角坐标
)
、图形尺寸、鼠标点于图形位置的偏移、是否选中图形的标记。
注意:逻辑坐标和设备坐标的转换。
保存的图形坐标、尺寸为逻辑坐标;
用
DC
来画图用的是逻辑坐标;
创建的可选中区域和判断鼠标点再区域内用设备坐标;
得到鼠标点相对图形的偏移是设备坐标;
擦除矩形用设备坐标。
新建一个单文档应用程序,
View
类继承自
CScrollView
带滚动条。
一、在工程
View
类中添加数据成员:
protected:
const CSize m_sizeEllipse; //
所绘制图形的尺寸
CPoint m_pointTopLeft; //
所绘制图形左上角点的坐标
CSize m_sizeOffset; //
鼠标的位置相对于图形左上角的偏移
BOOL m_bCaptured; //
图形是否被选中的标记
二、在工程
View
类的构造函数中初始化这些数据成员:
CMoveSelObView:: CMoveSelObView () : m_sizeEllipse(100, -100),
m_pointTopLeft(0, 0),
m_sizeOffset(0, 0)
{
m_bCaptured = FALSE;
}
三、在
View
类的
OnInitialUpdate
函数中设置滚动条的属性:(如果不用带滚动条的窗口,这些不是必需的,但必需设定映射模式)
void CMoveSelObView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
//
设置滚动范围
CSize sizeTotal(800, 1050); // 8-by-10.5 inches
CSize sizePage(sizeTotal.cx / 2, sizeTotal.cy / 2);
CSize sizeLine(sizeTotal.cx / 50, sizeTotal.cy / 50);
SetScrollSizes(MM_LOENGLISH, sizeTotal, sizePage, sizeLine);
}
四、在
View
的
OnDraw
函数中绘制一个用于拖动的图形:
void CMoveSelObView::OnDraw(CDC* pDC)
{
CMoveSelObDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//
创建红色画刷
CBrush brushHatch(HS_DIAGCROSS , RGB(255, 0, 0));
CPoint point(0, 0);
//
转换逻辑坐标到设备坐标
pDC->LPtoDP(&point);
pDC->SetBrushOrg(point); //
以设备坐标为参数
CBrush* pOldBrush = pDC->SelectObject(&brushHatch);
//
画红色圆圈
pDC->Ellipse(CRect(m_pointTopLeft, m_sizeEllipse));
pDC->SelectObject(pOldBrush);
}
五、在
View
类中添加
WM_LBUTTONDOWN
的消息响应,在其中创建可选中区域、启动鼠标捕捉、更新选中图形标记、计算鼠标相对图形的偏移、改变光标形状:
void CMoveSelObView::OnLButtonDown(UINT nFlags, CPoint point)
{
CRect rectEllipse(m_pointTopLeft, m_sizeEllipse);
CRgn circle;
CClientDC dc(this);
OnPrepareDC(&dc); //
准备好设备上下文,通知设备的映射模式(由
SetScrollSizes
指定)
dc.LPtoDP(rectEllipse); //
逻辑坐标转换为设备坐标
circle.CreateEllipticRgnIndirect(rectEllipse); //
创建用于选中的区域(参数要求逻辑坐标)
if (circle.PtInRegion(point)) //
点在区域内
{
//
捕捉鼠标
SetCapture(); //
将鼠标捕获设置到窗口
m_bCaptured = TRUE;
CPoint pointTopLeft(m_pointTopLeft);
dc.LPtoDP(&pointTopLeft);
m_sizeOffset = point - pointTopLeft; //
得到鼠标位置相对于图形左上角的偏移,设备坐标
//
设置光标形状为十字状
::SetCursor(::LoadCursor(NULL, IDC_CROSS));
}
CScrollView::OnLButtonDown(nFlags, point);
}
六、在
View
中添加
WM_MOUSEMOVE
消息的响应函数。如果图形被选中,在鼠标移动时调用
2
个
InvalidateRect
函数,前一个用来擦除旧图形,后一个用来显示新图形。
void CMoveSelObView::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bCaptured)
{//
如果有图形被选中,并且鼠标被捕捉则更新图形位置
CClientDC dc(this);
OnPrepareDC(&dc);
CRect rectOld(m_pointTopLeft, m_sizeEllipse);
dc.LPtoDP(rectOld);
//
擦除老位置的图形
InvalidateRect(rectOld, TRUE);
m_pointTopLeft = point - m_sizeOffset; //
更新图形左上角位置
dc.DPtoLP(&m_pointTopLeft);
//
在新位置画图形
CRect rectNew(m_pointTopLeft, m_sizeEllipse);
dc.LPtoDP(rectNew);
InvalidateRect(rectNew, TRUE);
}
CScrollView::OnMouseMove(nFlags, point);
}
七、在
View
中添加
WM_LBUTTONUP
消息的响应函数。释放鼠标左键,释放鼠标捕捉,清除图形选中标记:
void CMoveSelObView::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_bCaptured) {
//
释放鼠标捕捉
::ReleaseCapture();
m_bCaptured = FALSE;
}
CScrollView::OnLButtonUp(nFlags, point);
}