MFC对话框实现地图拖动效果(本文用的画图为例,可以拓展到控件)

地图拖动效果就是那种,你往哪拖,内容就跟着你往哪跑的,MFC的实现效果如下,我这里以拖动MFC对话框上的画图来作为示例的,其实我们还可以拓展到控件,在文末给出方法

实现效果如下图所示:( gif不动戳大 :) )

ezgif.com-video-to-gif

在这里我们主要处理3个对话框消息来实现地图的拖动效果。

WM_LBUTTONUP

WM_LBUTTONDOWN

WM_MOUSEMOVE

基本思路:当按下鼠标左键的时候标记当前状态为拖动状态,再记录当前鼠标位置用来计算平移的方向向量,然后,在WM_MOUSEMOVE消息函数里面通过判断当前状态来进行平移,最后当鼠标左键抬起时,再将当前状态设置为非拖动状态。

首先我们需要一个全局变量来储存当前状态(即是否处于拖动状态)

bool offset = false;    //用来记录当前状态
CPoint lbeg; //用来记录鼠标左键按下后的位置
CPoint last;

然后,我们处理WM_LBUTTONDOWN消息:

void CDTDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
offset = true;
lbeg = point;
SetCursor(LoadCursor(NULL, IDC_HAND)); //这行用来将光标设置为手的图标

CDialogEx::OnLButtonDown(nFlags, point);

}
然后,我们再处理WM_LBUTTONUP消息:

void CDTDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
offset = false;
lbeg = point;

CDialogEx::OnLButtonUp(nFlags, point);

}

平移对话框上的东西(我这里平移的是通过CDC画在对话框上的图案),其实就是不断的改变坐标进行重新绘制,所以,实现平移,我们需要在WM_MOUSEMOVE消息函数中实现坐标的变换,与图案的重绘。

为了方便,我们定义个函数,用来处理坐标变换,然后在WM_MOUSEMOVE消息中调用它,最后再在WM_MOUSEMOVE消息中实现重绘。

先贴上MoveMap函数的代码:

//地图平移函数,传入要平移的点集地址,平移方向,s是否将平移结果写入新文件,平移完毕后的点集文件路径,函数返回平移是否成功
const bool CDTDlg::MoveMap(const CString &psdir,const CPoint &vet, const bool newfile = false, const CString &todir = _T(“movemap.buf”))
{
CFile rawf, tof;
CPoint po;
if (!rawf.Open(psdir, CFile::modeReadWrite))
{
MessageBox(psdir + _T(“打开失败!”), _T(“MoveMap调试信息”), NULL);
return false;
}
if (!tof.Open(todir, CFile::modeReadWrite | CFile::modeCreate))
{
MessageBox(todir + _T(“打开失败!”), _T(“MoveMap调试信息”), NULL);
rawf.Close();
return false;
}
CString str;
while (rawf.Read(&po, sizeof(CPoint))>0)
{
po.x += (vet.x-1);
po.y += (vet.y
-1);
tof.Write(&po, sizeof(CPoint));
}
if (!newfile) //如果选择覆盖原文件
{
rawf.SeekToBegin();
tof.SeekToBegin();
while (tof.Read(&po, sizeof(CPoint))>0)
{
rawf.Write(&po, sizeof(CPoint));
}
//tof.SetLength(0); //清空文件
}
rawf.Close();
tof.Close();
return true;
}

先来说说参数:

第一个参数为要处理的点集文件。

第二个参数是方向向量

第三个是是否用变换后的数据覆盖原数据,默认覆盖

第三个参数是如果第三个参数选择不覆盖,则第四个参数应传入处理后的数据的存放地址

上面代码中,我们把mvet.x和mvet.y都乘以-1的原因的,其实很简单,如果不乘以-1的话,拖动方向会和你的实际拖动方向相反。

下面我们再处理WM_MOUSEMOVE函数:

void CDTDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CPoint mvet,draw,bbeg;
CClientDC dcd(this);
CPen pen(PS_SOLID, 4, RGB(225, 0, 0));
dcd.SelectObject(&pen);
if (offset) //平移
{
SetCursor(LoadCursor(NULL, IDC_HAND));
mvet.x = lbeg.x - point.x;
mvet.y = lbeg.y - point.y;
//在平移开始之前,首先我们要让off.set文件有内容
f.Open(_T(“off.set”), CFile::modeRead);
if (f.GetLength() <= 0)
{
f.Close();
if (!MoveMap(_T(“draw.draw”), CPoint(0,0), true, _T(“off.set”)))
{
MessageBox(_T(“无法完成地图平移!\n缓存检查失败”) _T(“错误”), NULL);
}
}
else
{
f.Close();
}
//qkong
CRect rect;
GetClientRect(rect);
dcd.FillSolidRect(rect, RGB(200, 200, 200));
//开始平移
if (!MoveMap(_T(“off.set”), mvet))
{
MessageBox(_T(“无法完成地图平移!”) _T(“错误”), NULL);
}
f.Open(_T(“off.set”), CFile::modeRead);
f.Read(&bbeg, sizeof(CPoint));
while (f.Read(&draw, sizeof(CPoint)) > 0)
{
dcd.MoveTo(bbeg);
dcd.LineTo(draw);
bbeg = draw;
}
f.Close();

    //
    lbeg = point;
}
CDialogEx::OnMouseMove(nFlags, point);

}
上面的代码中,我们将变换后的坐标放入off.set文件中然后我们再读取off.set中的数据来实现重绘。

最后我们把point的值赋给了lbeg,然后下一次WM_MOUSEMOVE函数相应的时候,lbeg的值为上一次WM_MOUSEMOVE相应的时候的point值,这样做是为了计算平移的方向向量。

 

 

 

0%