posted at 2016-04-25 15:00:06 +0000
地图拖动效果就是那种,你往哪拖,内容就跟着你往哪跑的,MFC的实现效果如下,我这里以拖动MFC对话框上的画图来作为示例的,其实我们还可以拓展到控件,在文末给出方法
实现效果如下图所示:( gif不动戳大 :) )
在这里我们主要处理3个对话框消息来实现地图的拖动效果。
WM_LBUTTONUP
WM_LBUTTONDOWN
WM_MOUSEMOVE
基本思路:当按下鼠标左键的时候标记当前状态为拖动状态,再记录当前鼠标位置用来计算平移的方向向量,然后,在WM_MOUSEMOVE
消息函数里面通过判断当前状态来进行平移,最后当鼠标左键抬起时,再将当前状态设置为非拖动状态。
首先我们需要一个全局变量来储存当前状态(即是否处于拖动状态)
bool offset = false; //用来记录当前状态
CPoint lbeg; //用来记录鼠标左键按下后的位置
CPoint last;
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值,这样做是为了计算平移的方向向量。
© kanch
→ zl AT kanchz DOT com
last updated on 2022-07-27 01:57:54 +0000