hcnak.blog

posted at 2016-04-25 15:00:06 +0000

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;

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值,这样做是为了计算平移的方向向量。



© kanchzl AT kanchz DOT com

last updated on 2022-07-27 01:57:54 +0000