方式一:
第1步-----重载ONEraseBkgnd, 直接返回FALS,不要自动刷新背景,避免平移闪烁
BOOL CImgView::OnEraseBkgnd(CDC* pDC) { // TODO: Add your message handler code here and/or call default return FALSE; //表示未处理背景刷新 }
第2步----左键按下消息
SetCapture(); //捕获鼠标 SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR_HANDOPEN));// 手形光标 m_prePoint = point; //记录下左键按下时的位置
if (nFlags&MK_LBUTTON){ m_ulPoint.x += point.x - m_prePoint.x; //图像移动后的新初始位置 m_ulPoint.y += point.y - m_prePoint.y; InvalidateRect(m_imgRec); //更新客户区 }
void CImgView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default ReleaseCapture(); CView::OnLButtonUp(nFlags, point); }
方式二:
平移图像,要响应三个消息
鼠标按下: 目的是记录刚按下时鼠标位置
鼠标移动: 此时鼠标位置-按下时的鼠标位置即为移动偏移量
鼠标UP: 重置变量值。
为此,需要3个全局变量:
m_Point ----------------->目标图片的左上角
m_LbtndownP----------->左键刚按下时的坐标
m_PreP-------------------->移动之前的点的坐标,这个变量在鼠标移动时使用,在鼠标UP时重置
原理分析:
移动过程中,为使得图片正确移动,关键是如何得到移动后图片坐标m_Point, 为此,我们必须先求出移动偏移量,而要求移动偏移量,必先知道左键刚按下时的坐标m_LbtndownP;而当我们知道量后偏移,下一步工作就是反推出当前目标图片坐标,由于偏移量是相对于移动之前的图片,因此,我们必须记录下移动之前的图片坐标m_PreP,才能推出现在目标图片的坐标
以下是各个程序:
变量定义:
public: Image *m_pImage; Bitmap *m_pBmp; CPoint m_Point; CPoint m_LbtndownP; CPoint m_PreP;
变量初始化:
CImageView::CImageView() { m_pImage=NULL; m_pBmp=NULL; m_Point.x=m_Point.y=0; m_PreP=m_LbtndownP=m_Point; }
左键按下消息:
void CImageView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_LbtndownP=point; CView::OnLButtonDown(nFlags, point); }
鼠标移动消息:
void CImageView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if ((nFlags&MK_LBUTTON)==MK_LBUTTON) { if (GetPixel(GetDC()->GetSafeHdc(),point.x,point.y)!=RGB(255,255,255)) // 判断鼠标是否在图片上,判断方法可自行修改 { m_Point.x=m_PreP.x+(point.x-m_LbtndownP.x); m_Point.y=m_PreP.y+(point.y-m_LbtndownP.y); Invalidate(FALSE); } } CView::OnMouseMove(nFlags, point); }
鼠标UP消息:
void CImageView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_PreP=m_Point; CView::OnLButtonUp(nFlags, point); }
OnDraw函数:void CImageView::OnDraw(CDC* pDC) { CDocument* pDoc = GetDocument(); // TODO: 在此添加绘制代码 CRect rect; GetClientRect(&rect); if (m_pImage!=NULL) { if(m_pBmp==NULL) // OnSize中 delete掉m_pBmp 否则放大对话框时有问题,因为m_pBmp还是原来的尺寸,所以放大可能出现问题 { m_pBmp=new Bitmap(rect.Width(),rect.Height()); } Graphics gbmp(m_pBmp); gbmp.Clear(Color(255,255,255,255)); gbmp.DrawImage(m_pImage,m_Point.x,m_Point.y); Graphics g(GetDC()->m_hDC); g.DrawImage(m_pBmp,0,0); }else{ GetDC()->FillSolidRect(rect,RGB(255,255,255)); } }
以下是整体程序:
.h头文件
#pragma once // CImageView 视图 class CImageView : public CView { DECLARE_DYNCREATE(CImageView) protected: CImageView(); // 动态创建所使用的受保护的构造函数 virtual ~CImageView(); public: virtual void OnDraw(CDC* pDC); // 重写以绘制该视图 #ifdef _DEBUG virtual void AssertValid() const; #ifndef _WIN32_WCE virtual void Dump(CDumpContext& dc) const; #endif #endif protected: DECLARE_MESSAGE_MAP() protected: GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; public: virtual void OnInitialUpdate(); public: Image *m_pImage; Bitmap *m_pBmp; CPoint m_Point; CPoint m_LbtndownP; CPoint m_PreP; public: afx_msg BOOL OnEraseBkgnd(CDC* pDC); public: afx_msg void OnMouseMove(UINT nFlags, CPoint point); public: afx_msg void OnLButtonDown(UINT nFlags, CPoint point); public: afx_msg void OnLButtonUp(UINT nFlags, CPoint point); public: afx_msg void OnSize(UINT nType, int cx, int cy); };
.cpp源文件// ImageView.cpp : 实现文件 // #include "stdafx.h" #include "TreePath.h" #include "ImageView.h" // CImageView IMPLEMENT_DYNCREATE(CImageView, CView) CImageView::CImageView() { m_pImage=NULL; m_pBmp=NULL; m_Point.x=m_Point.y=0; m_PreP=m_LbtndownP=m_Point; } CImageView::~CImageView() { if (m_pImage!=NULL) { delete m_pImage; m_pImage=NULL; } GdiplusShutdown(gdiplusToken); } BEGIN_MESSAGE_MAP(CImageView, CView) ON_WM_ERASEBKGND() ON_WM_MOUSEMOVE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_SIZE() END_MESSAGE_MAP() // CImageView 绘图 /* RectF rc; rc.X=rect.left; rc.Y=rect.top; rc.Width=rect.Width(); rc.Height=rect.Height(); gbmp.DrawImage(m_pImage,rc,0,0,m_pImage->GetWidth(),m_pImage->GetHeight(),UnitPixel); */ void CImageView::OnDraw(CDC* pDC) { CDocument* pDoc = GetDocument(); // TODO: 在此添加绘制代码 CRect rect; GetClientRect(&rect); if (m_pImage!=NULL) { if(m_pBmp==NULL) // OnSize中 delete掉m_pBmp 否则放大对话框时有问题,因为m_pBmp还是原来的尺寸,所以放大可能出现问题 { m_pBmp=new Bitmap(rect.Width(),rect.Height()); } Graphics gbmp(m_pBmp); gbmp.Clear(Color(255,255,255,255)); gbmp.DrawImage(m_pImage,m_Point.x,m_Point.y); Graphics g(GetDC()->m_hDC); g.DrawImage(m_pBmp,0,0); }else{ GetDC()->FillSolidRect(rect,RGB(255,255,255)); } } // CImageView 诊断 #ifdef _DEBUG void CImageView::AssertValid() const { CView::AssertValid(); } #ifndef _WIN32_WCE void CImageView::Dump(CDumpContext& dc) const { CView::Dump(dc); } #endif #endif //_DEBUG // CImageView 消息处理程序 void CImageView::OnInitialUpdate() { CView::OnInitialUpdate(); GdiplusStartup(&gdiplusToken,&gdiplusStartupInput,NULL); // TODO: 在此添加专用代码和/或调用基类 } BOOL CImageView::OnEraseBkgnd(CDC* pDC) { // TODO: 在此添加消息处理程序代码和/或调用默认值 return FALSE; return CView::OnEraseBkgnd(pDC); } void CImageView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if ((nFlags&MK_LBUTTON)==MK_LBUTTON) { if (GetPixel(GetDC()->GetSafeHdc(),point.x,point.y)!=RGB(255,255,255)) // 判断鼠标是否在图片上,判断方法可自行修改 { m_Point.x=m_PreP.x+(point.x-m_LbtndownP.x); m_Point.y=m_PreP.y+(point.y-m_LbtndownP.y); Invalidate(FALSE); } } CView::OnMouseMove(nFlags, point); } void CImageView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_LbtndownP=point; CView::OnLButtonDown(nFlags, point); } void CImageView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_PreP=m_Point; CView::OnLButtonUp(nFlags, point); } void CImageView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); if(m_pBmp) delete m_pBmp; m_pBmp=NULL; // Invalidate(FALSE); // TODO: 在此处添加消息处理程序代码 }