各位大虾好:
   
  在MFC中如何实现用鼠标拖动我已经绘制在视图上的图形?     在WM_LBUTTONDOWN和WM_LBUTTONMOVE中要做点什么?能给点代码参考吗?先谢过各位大虾了。    补充:我画在视图上的图形保存在一个结构体数组中。

解决方案 »

  1.   

    如果不需要点选的话,可以down中记录下当前鼠标位置,再在MOVE中用其移动的偏移计算移动的位置,然后再重绘就可以了
      

  2.   

    小弟要在DOWN中判断这个点是否在图形内,如果在,我是否要判断当前的图形是在我之前保存图形的数组的哪个?然后在MOVE中对这个图形重绘吗?麻烦大虾能说的详细点吗? 多谢多谢。
      

  3.   

    是的.要判断在哪个里了..所以你的数组要保留有图形的大小位置等,首先判断是否在图形内.
    如果在了.拖动的过程中第一步是清除图形.如果你的图形有覆盖的话,别的图形要重绘..
    然后move了以后重新绘制.
      

  4.   

    给你一个基本模板,里面代码我简化了,可能有错误,大致思路不会错,需要GDI+支持。
    我的方法是建立自己的类来完成,图形操作。
    类声明:
    class CMX
    {
    public:
        void   Draw  ( CDC *pdc ); //绘图函数,在使用该类的OnDraw中调用
        void   SetRn ( CDC *pdc ); //设定区域函数,每一次绘图都要根据点的位置重新设定区域
        void   RtTo  ( CDC *pdc, PointF orpos, PointF nwpos ); //旋转函数,点的类型、旋转机制不同算法不同
        void   DrTo  ( CDC *pdc, PointF orpos, PointF nwpos ); //平移函数,不多说了
        void   OnMMv ( CDC *pdc, PointF point ); //键盘操作函数,在那里用肯定知道
        void   OnMUp ( CDC *pdc, PointF point );
        void   OnMDn ( CDC *pdc, PointF point );

        CArray <PointF,PointF> m_Lst;  //点集,也就是你说的数组    BOOL Sted;  //区域和标志,根据区域来判断标志,由标志可以知道该类的操作
        BOOL Rted;    BOOL DF;
        BOOL DR;    Region RtRn;
        Region StRn;    PointF DPt;
        PointF Bpt;    CMX();
       virtual ~CMX();
    private:

    };类实现:
    void CMX::OnMDn(CDC *pdc, PointF point)
    {
    DF=TRUE;
    DPt=point;
    Bpt=point; Sted=FALSE;
    Rted=FALSE; if(StRn.IsVisible(point.X,point.Y,NULL)){ Sted=TRUE; } if(RtRn.IsVisible(point.X,point.Y,NULL)){ Rted=TRUE; }
    }void CMX::OnMUp(CDC *pdc, PointF point)
    {
    DF=FALSE;
    IsDw=FALSE;
            //这里有一个函数没写,也就是重新给点集赋值的函数,因为这里是可选的,你也可以直接在旋转或平移函数中赋值
    }void CMX::OnMMv(CDC *pdc, PointF point)
    {
    if(DF==TRUE){ DR=TRUE; }else{ DR=FALSE; }
    if(DR==TRUE && Sted==TRUE){ DrTo(pdc,Bpt,point);
    Bpt=point;

    }else if(DR==TRUE && Rted==TRUE){

    RtTo(pdc, Dpt, point);
    }
    }void CMX::Draw(CDC *pdc)
    {
    if(Sted==FALSE && Rted==FALSE)
    {
    DrawNm(pdc);
    SetRn(pdc); }else if(Sted==TRUE){ DrawSt(pdc);
    SetRn(pdc); }else if( Rted==TRUE ){ DrawRt(pdc);
    SetRn(pdc);
    }
    }
      

  5.   

    我说一个比较简单的思路,
    1,先谈谈你的那个 结构体数组,该结构体中一定要包含一个区域的值,即你的图形的所在区域。
    2.当鼠标左键按下时,取得鼠标的位置,然后在结构体数组中进行搜索,该点是否在区域内,是,
     说明是选中的该图形
    3,在onmousemove中,改变区域的值,并重绘结构体数组中的图形。(简易采用双缓冲,否则会有闪烁的现象)。
      

  6.   

    用橡皮筋类:mfc有的,可以支持拖动。
    不用你处理消息。
      

  7.   

    小弟由于白天暂时不能上网,只好晚上跑网吧看大家的指导....我仔细的看了Tinary3v0给的CODE,还是挺晕的,我能理解大致思路,就是看到那几个判断标志就晕了,能具体的说下么(我是初学者 呵呵),或者给我推荐个资料我自己看也行!!
      

  8.   

    hucailai大虾说的这个完整了我的基本思路,说下我的那个数组里有些:画图形时(直线,巨型,圆)的点,线宽,线色,选择画什么图形的DrawType。
    我的问题:
    ***1.我一时搞不清你说的”图形所在区域“是”CClient rect"这个吗?还是?   ***2.当鼠标左键按下时,我想把DOWN的点所落在的那个图形的数组下标传到UP里,在UP里重绘这个下标的图形,不知道可否?如果可以,我实现的时候在LBUTTONDOWN里,只写了个判断点如在图形内,则把下标附给一个成员变量。然后,我运行后,一点鼠标左键,我的窗口就自动关了! 什么情况?
      

  9.   

    你对图形的操作全部可以通过鼠标事件的判断来得到。举一个简单的例子,“拖动”:
    拖动的思路是这样的:
    1.鼠标落下的时候判断在什么区域当中。 比如一个矩形区域区域里面,你要是不懂得gdi+的Region,那你就用GDI的CRgn类来建立矩形的拖动区域。我习惯将这些区域设置成全局变量,6楼的方法应该是建立局部变量来判断也是可以的。 如果鼠标落在选中区域,那么就应该将图形的选中标志Sted设置为TRUE,说明当前图形处于选中状态。
    2.另外就是鼠标落下DF和鼠标拖动标志DR的判断,很明显,如果你想拖动一个图形移动,首先你要点中这个图形,这个时候DF为TRUE,在鼠标移动的时候判断DF是不是TRUE,不就可以知道鼠标是不是处于拖懂状态了么。 如果在Move中发现图形处于选中状态,同时鼠标又处于拖动状态,那么就执行图形移动操作。
    就是上面move中的这段代码的意思:
    if(DR==TRUE && Sted==TRUE)
    {
        DrTo(pdc,Bpt,point);  //这里我使用的是鼠标移动前一个点Bpt,如果使用鼠标落下的点Dpt,函数里面使用的算法稍有差别。
        Bpt=point;   
    }
    3.在DrTo这个代码中我一般是通过鼠标落下的点与鼠标移动的当前点这两个点,来计算图形当前所应该在的位置。这个时候,我会绘制一个图形的虚框,就好像Word里面拖动文本框时候出现的那种;但是移动的时候我会对你说的数组中的数据进行赋值的。 而且DrTo这个函数我一般会带有返回值,也就是我在Up中所说的那样,拖动的时候不赋值,我会在Up中最后赋值给数组。如果你用GDI开发这个可以减少偏差。Up时候当然需要对鼠标的标志DF、DR置成FALSE的。说了这么多,楼主还是需要自己多动手去做啊!
      

  10.   

    我也想做一个这方面的软件,实现CAD中的部分功能。不知用什么语方最简单。VB能否可行。
    我先说说我的思路。
    CAD中最基本图形就是直线段和圆弧。
    画图需用橡皮筋功能,这样才显得高级。
    记录如下特征:直线:起点、终点
                    圆:圆心、半径
                  圆弧:圆心、半径、起点度数、终点度数。选中已画好的图形:1、鼠标点击选择,计算该点是否落在图线的垂直阴影内,
                                       在就计算距图形的最近距离,取最近一个,
                                           在判断是否满足设定的距离要求,满足就选中
                                       不在就计算距端点的距离,取最近一个,
                                           在判断是否满足设定的距离要求,满足就选中                                       
      

  11.   

    14楼的这些功能都能实现,但是你说的选中物体的过程太过于复杂了。
    判断鼠标是否选中一个图形其实不用算法也很容易实现的。 如果用GDI的话用CRgnCRgn hRgn; //矩形区域
    pdc->BeginPath(); 
    pdc->MoveTo(左上点); 
    pdc->LineTo(右上点); 
    pdc->LineTo(右下点); 
    pdc->LineTo(左下点); 
    pdc->LineTo(左上点); 
    pdc->CloseFigure();  
    pdc->EndPath();  
    hRgn.CreateFromPath(pdc);GDI+的话用Region,GDI+应该比较好用,14楼的方法如果是规则图形(圆、矩形、直线),用GDI或这算法还是很容易实现的,但是
    要是没法子用方程标示的曲线,那就麻烦了,就像我下面添加的Curve曲线,你很难往上面做垂线的(当然也能,但是很复杂)。这个
    时候GDI+就看出它的厉害之处了。看下面代码:
    PointF PTC[10]; 
    PTC[1]=PointF(100.0,100.0);
    ......
    PTC[9]=PointF(100.0,100.0);GraphicsPath path;
    path.AddLine(Pt1,Pt2); //向路径中添加一条直线
    path.AddCurve(PTC,10); //向路径中添加一条Curve,很像是Word中的曲线Pen greenPen(Color(255,0,0,0),12);  //建立一个画笔,画笔的宽度就是你要选中这条路径时,有效点距离这个路径的长度(其实是2倍)
    path.Widen(&greenPen);    //用画笔扩充路径
    Region sctRgn(&path);     //通过路径建立一个区域,由于路径被扩张了,所以这个区域的样子就好像是以前路径用了一个更粗的画笔画了一边一样。if( sctRgn.IsVisible(point.X,point.Y) = TRUE ) 
    {
        //选中了
    }else{
        //没有选中
    }另外,使用那种工具来编应该不是大问题,看你熟悉那个了。
      

  12.   

    LZ兄弟,MSDN有个示例,叫DrawCli
    你需要的里面全有。仔细研究一下吧。
      

  13.   


    // CEx4ViewIMPLEMENT_DYNCREATE(CEx4View, CScrollView)BEGIN_MESSAGE_MAP(CEx4View, CScrollView)
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_MOUSEMOVE()
    END_MESSAGE_MAP()// CEx4View 构造/析构CEx4View::CEx4View()
    : m_pointTopLeft(0, 0), m_sizeEllipse(100, -100),
    m_sizeOffset(0, 0), m_bCaptrued(FALSE)
    {
    // TODO: 在此处添加构造代码}CEx4View::~CEx4View()
    {
    }BOOL CEx4View::PreCreateWindow(CREATESTRUCT& cs)
    {
    // TODO: 在此处通过修改
    //  CREATESTRUCT cs 来修改窗口类或样式 return CScrollView::PreCreateWindow(cs);
    }// CEx4View 绘制void CEx4View::OnDraw(CDC* pDC)
    {
    /*CEx4Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
    return;*/ CBrush brushHatch(HS_DIAGCROSS, RGB(255, 0, 0));
    CPoint point(0, 0); pDC->SelectObject(&brushHatch);
    pDC->Ellipse(CRect(m_pointTopLeft, m_sizeEllipse)); pDC->SelectStockObject(BLACK_BRUSH);
    pDC->Rectangle(CRect(100, -100, 200, -200)); // TODO: 在此处为本机数据添加绘制代码
    }void CEx4View::OnInitialUpdate()
    {
    CScrollView::OnInitialUpdate(); CSize sizeTotal(800, 1050);
    CSize sizePage(sizeTotal.cx/2, sizeTotal.cy/2);
    CSize sizeLine(sizeTotal.cx/50, sizeTotal.cy/50); SetScrollSizes(MM_LOENGLISH, sizeTotal, sizePage, sizeLine);
    }void CEx4View::OnLButtonDown(UINT nFlags, CPoint point)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    CRect rectEllipse(m_pointTopLeft, m_sizeEllipse);
    CRgn circle; CClientDC dc(this);
    OnPrepareDC(&dc);
    dc.LPtoDP(rectEllipse);
    circle.CreateEllipticRgnIndirect(rectEllipse);
    if(circle.PtInRegion(point))
    {
    SetCapture();
    m_bCaptrued = TRUE; CPoint pointTemp(m_pointTopLeft);
    dc.LPtoDP(&pointTemp);
    m_sizeOffset = point - pointTemp; ::SetCursor(::LoadCursor(NULL, IDC_CROSS));
    }

    CScrollView::OnLButtonDown(nFlags, point);
    }void CEx4View::OnLButtonUp(UINT nFlags, CPoint point)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    if(m_bCaptrued)
    {
    ReleaseCapture();
    m_bCaptrued = FALSE;
    }
    CScrollView::OnLButtonUp(nFlags, point);
    }void CEx4View::OnMouseMove(UINT nFlags, CPoint point)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    if (m_bCaptrued)
    {
    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);
    InvalidateRect(rectNew, TRUE);
    }
    CScrollView::OnMouseMove(nFlags, point);
    }
      

  14.   

    // Ex4View.cpp : CEx4View 类的实现
    //#include "stdafx.h"
    #include "Ex4.h"#include "Ex4Doc.h"
    #include "Ex4View.h"#ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    // CEx4ViewIMPLEMENT_DYNCREATE(CEx4View, CScrollView)BEGIN_MESSAGE_MAP(CEx4View, CScrollView)
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_MOUSEMOVE()
    END_MESSAGE_MAP()// CEx4View 构造/析构CEx4View::CEx4View()
    : m_pointTopLeft(0, 0), m_sizeEllipse(100, -100),
    m_sizeOffset(0, 0), m_bCaptrued(FALSE)
    {
    // TODO: 在此处添加构造代码}CEx4View::~CEx4View()
    {
    }BOOL CEx4View::PreCreateWindow(CREATESTRUCT& cs)
    {
    // TODO: 在此处通过修改
    //  CREATESTRUCT cs 来修改窗口类或样式 return CScrollView::PreCreateWindow(cs);
    }// CEx4View 绘制void CEx4View::OnDraw(CDC* pDC)
    {
    /*CEx4Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
    return;*/ CBrush brushHatch(HS_DIAGCROSS, RGB(255, 0, 0));
    CPoint point(0, 0); pDC->SelectObject(&brushHatch);
    pDC->Ellipse(CRect(m_pointTopLeft, m_sizeEllipse)); pDC->SelectStockObject(BLACK_BRUSH);
    pDC->Rectangle(CRect(100, -100, 200, -200)); // TODO: 在此处为本机数据添加绘制代码
    }void CEx4View::OnInitialUpdate()
    {
    CScrollView::OnInitialUpdate(); CSize sizeTotal(800, 1050);
    CSize sizePage(sizeTotal.cx/2, sizeTotal.cy/2);
    CSize sizeLine(sizeTotal.cx/50, sizeTotal.cy/50); SetScrollSizes(MM_LOENGLISH, sizeTotal, sizePage, sizeLine);
    }
    // CEx4View 诊断#ifdef _DEBUG
    void CEx4View::AssertValid() const
    {
    CScrollView::AssertValid();
    }void CEx4View::Dump(CDumpContext& dc) const
    {
    CScrollView::Dump(dc);
    }CEx4Doc* CEx4View::GetDocument() const // 非调试版本是内联的
    {
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CEx4Doc)));
    return (CEx4Doc*)m_pDocument;
    }
    #endif //_DEBUG
    // CEx4View 消息处理程序void CEx4View::OnLButtonDown(UINT nFlags, CPoint point)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    CRect rectEllipse(m_pointTopLeft, m_sizeEllipse);
    CRgn circle; CClientDC dc(this);
    OnPrepareDC(&dc);
    dc.LPtoDP(rectEllipse);
    circle.CreateEllipticRgnIndirect(rectEllipse);
    if(circle.PtInRegion(point))
    {
    SetCapture();
    m_bCaptrued = TRUE; CPoint pointTemp(m_pointTopLeft);
    dc.LPtoDP(&pointTemp);
    m_sizeOffset = point - pointTemp; ::SetCursor(::LoadCursor(NULL, IDC_CROSS));
    }

    CScrollView::OnLButtonDown(nFlags, point);
    }void CEx4View::OnLButtonUp(UINT nFlags, CPoint point)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    if(m_bCaptrued)
    {
    ReleaseCapture();
    m_bCaptrued = FALSE;
    }
    CScrollView::OnLButtonUp(nFlags, point);
    }void CEx4View::OnMouseMove(UINT nFlags, CPoint point)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    if (m_bCaptrued)
    {
    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);
    InvalidateRect(rectNew, TRUE);
    //Invalidates the client area within the given 
    //rectangle by adding that rectangle to the CWnd update region. //UpdateWindow();
    //Updates the client area by sending a WM_PAINT
    //message if the update region is not empty. //The UpdateWindow member function sends a WM_PAINT 
    //message directly, bypassing the application queue.
    //If the update region is empty, WM_PAINT is not sent. //Invalidate(FALSE);
    // Invalidates the entire client area of CWnd.
    }
    CScrollView::OnMouseMove(nFlags, point);
    }
    //抱歉 刚才没贴好