我指的不是拖拽文件,是指的拖拽文本:包括拖拽他自己里面的文本,和拖拽其它地方的文本到它里面来。

解决方案 »

  1.   

    网上有这样的类 CDragEdit//////////////////////////////////////
    //
    // Author : Sam Lu
    // E-mail : [email protected]
    //#if !defined(AFX_CDRAGEDIT_H__871E3CD6_6359_11D1_8251_444553540000__INCLUDED_)
    #define AFX_CDRAGEDIT_H__871E3CD6_6359_11D1_8251_444553540000__INCLUDED_#if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000
    // CDragEdit.h : header file
    ///////////////////////////////////////////////////////////////////////////////
    // CDragEdit window
    #include <afxole.h>class CDragEdit;class CDEDropTarget : public COleDropTarget
    {
    public:
        CDEDropTarget()
            {
            ms_bBeginDrop=FALSE;
            ms_pEditCtl=NULL;
            }
        BOOL        Register(CDragEdit* pEdit);
        BOOL        OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);
        DROPEFFECT  OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
        void        OnDragLeave(CWnd* pWnd);
        DROPEFFECT  OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
        DROPEFFECT  OnDragScroll(CWnd* pWnd, DWORD dwKeyState, CPoint point);private:
        BOOL        ms_bBeginDrop;
        CDragEdit*  ms_pEditCtl;
    };class CDEDataSource : public COleDataSource
    {
    };#define CDragEditBase   CEditclass CDragEdit : public CDragEditBase
    {
    // Construction
    public:
    CDragEdit();// Attributes
    public:
        enum {  DE_ENABLE_DRAG=1, 
                DE_ENABLE_DROP=2
        };private:
        static  BOOL    ms_bOleInit;    BOOL            ms_bDragInit;    int             ms_nEnableFlags;    BOOL            ms_bInDragging;    BOOL            ms_bDropEqualDrag;
        int             ms_nDropPtLine;
        int             ms_nDropPtPos; CDEDropTarget ms_dropTarget;
    CDEDataSource ms_dropSource;// Operations
    public:
        BOOL    Init(int nFlags=(DE_ENABLE_DRAG|DE_ENABLE_DROP));    BOOL    IsInDragging()                  {return ms_bInDragging;}
        void    SetDropEqualDrag(BOOL bEqual)   {ms_bDropEqualDrag=bEqual;}
        void    SetDropPos(int nLine, int nPos) {ms_nDropPtLine=nLine, 
                                                 ms_nDropPtPos=nPos;}    BOOL    GetCurRange(int& nLine1, int& nPos1, int& nLine2, int& nPos2);
        BOOL    GetLinePosByCursor(int& nLine, int& nPos);    BOOL    SetCaretByCursor();
        BOOL    SetCaret(int nLine, int nPos);    BOOL    DrawCaretByCursor();    CPoint  GetPosFromLinePos(int nLine, int nPos)  
                    {return PosFromChar(_LinePosToChar(nLine,nPos));}
        //we reimpelmented this function for fixing SDK's bug
        CPoint  PosFromChar(UINT uChar);    BOOL    IsInSelRange();    BOOL    EnableDrag()    
                    {return (ms_nEnableFlags & DE_ENABLE_DRAG) ? TRUE : FALSE;}
        BOOL    EnableDrop()    
                    {return (ms_nEnableFlags & DE_ENABLE_DROP) ? TRUE : FALSE;}
        private:
        BOOL    _GetSelText(CString& str);
        void    _CharToLinePos(int nChar, int* pnLine, int* pnPos)
                    {
                    if (nChar<0) nChar=0;
                    *pnLine=LineFromChar(nChar);
                    *pnPos=nChar-LineIndex(*pnLine);
                    }
        int     _LinePosToChar(int nLine, int nPos) {return LineIndex(nLine)+nPos;}
    // Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CDragEdit)
    //}}AFX_VIRTUAL// Implementation
    public:
    virtual ~CDragEdit(); // Generated message map functions
    protected:
    //{{AFX_MSG(CDragEdit)
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
    afx_msg void OnDestroy();
    //}}AFX_MSG DECLARE_MESSAGE_MAP()
    };///////////////////////////////////////////////////////////////////////////////{{AFX_INSERT_LOCATION}}
    // Microsoft Developer Studio will insert additional declarations immediately before the previous line.#endif // !defined(AFX_CDRAGEDIT_H__871E3CD6_6359_11D1_8251_444553540000__INCLUDED_)// CDragEdit.cpp : implementation file
    //
    // Author : Sam Lu
    // E-mail : [email protected]
    //#include "stdafx.h"
    #include "CDragEdit.h"#ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif#define MAXLINELEN 2048enum {
        DE_INSEL, DE_BEFORESEL, DE_AFTERSEL
    };/////////////////////////////////////////////////////////////////////////////
    // CDragEditCDragEdit::CDragEdit()
    {
        ms_bDragInit=FALSE;
        ms_nEnableFlags=0;
        ms_bInDragging=FALSE;
        ms_bDropEqualDrag=FALSE;
    }CDragEdit::~CDragEdit()
    {
    }
    BEGIN_MESSAGE_MAP(CDragEdit, CDragEditBase)
    //{{AFX_MSG_MAP(CDragEdit)
    ON_WM_LBUTTONDOWN()
    ON_WM_SETCURSOR()
    ON_WM_DESTROY()
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
    // CDragEdit message handlers
    BOOL CDragEdit::ms_bOleInit=FALSE;BOOL CDragEdit::Init(int nFlags) 
    {
        if (!ms_bOleInit) {
     //       if (!AfxOleInit()) {
     //           TRACE("Fail in OLE initialating\n");
     //           return FALSE;
     //       }
            ms_bOleInit=TRUE;
        }    if (ms_bDragInit) return FALSE;    ms_nEnableFlags=nFlags;    if (!GetSafeHwnd()) {
            TRACE("You should create CDragEdit first, before this function is called\n");
    return FALSE;
        }
    if (!ms_dropTarget.Register(this)) {
    TRACE("Fail in registing drop target\n");
    return FALSE;
    }
        ms_bDragInit=TRUE;
    return TRUE;
    }//we reimpelmented this function for fixing SDK's bug that
    //it always returns (-1,-1) when the uChar is the last char
    CPoint CDragEdit::PosFromChar(UINT uChar)
    {
        if (0==uChar)
            return CPoint(0,0);
        CPoint pt=CDragEditBase::PosFromChar(uChar);
        if (pt.x<0 && pt.y<0) {
            int nLine, nPos;
            _CharToLinePos((int)uChar,&nLine,&nPos);
            //get dc and select current using font
            CClientDC dc(this);
            dc.SelectObject(GetFont());
            //get position of previous char
            pt=CDragEditBase::PosFromChar(uChar-1);        
            if (nPos==0) {
                //if current char is the first char
                //we get the current y from previous y plus font height
                CSize szFont=dc.GetTextExtent("A",1);
                pt.y+=szFont.cy;
                pt.x=0;
            }
            else {
                char szBuf[MAXLINELEN];
                GetLine(nLine,szBuf,sizeof(szBuf));
                CSize szFont=dc.GetTextExtent(&szBuf[nPos-1],1);
                pt.x+=szFont.cx;
            }
            dc.SelectStockObject(SYSTEM_FONT);
        }
        return pt;
    }
      

  2.   


    //get line and pos information from current selection range
    BOOL CDragEdit::GetCurRange(int& nLine1, int& nPos1, int& nLine2, int& nPos2)
    {
        //get current selection range
        GetSel(nPos1,nPos2);
        //and trans. to line, pos
        _CharToLinePos(nPos1,&nLine1,&nPos1);
        _CharToLinePos(nPos2,&nLine2,&nPos2);
        return TRUE;
    }//get line and pos from current cursor position
    //return TRUE, if cursor is exactly at a char
    //return FALSE, if cursor is at white space area
    BOOL CDragEdit::GetLinePosByCursor(int& nLine, int& nPos)
    {
        CPoint ptCursor;
        GetCursorPos(&ptCursor);
        ScreenToClient(&ptCursor);    nPos=(int)(short)LOWORD((DWORD)CharFromPos(ptCursor));
        if (nPos<0) nPos=0;
        _CharToLinePos(nPos,&nLine,&nPos);    //the following codes will check if cusor is at white space area
        //get the maximum x of nLine
        CPoint ptChar;
        ptChar=PosFromChar(LineIndex(nLine)+LineLength(LineIndex(nLine)));
        if (ptChar.x<ptCursor.x || ptCursor.x<0)
            return FALSE;
        return TRUE;
    }//set edit's caret position by current cursor position
    BOOL CDragEdit::SetCaretByCursor()
    {
        //get cursor's position and translate it to client coordinate
        CPoint ptCursor;
        GetCursorPos(&ptCursor);
        ScreenToClient(&ptCursor);
        //set caret position
        int nChar=(int)LOWORD((DWORD)CharFromPos(ptCursor));
        SetSel(nChar,nChar);
        return TRUE;
    }BOOL CDragEdit::SetCaret(int nLine, int nPos)
    {
        int nChar=_LinePosToChar(nLine,nPos);
        SetSel(nChar,nChar);
        return TRUE;
    }//draw a caret at current cursor position
    //this function will not affect the caret position or selection status
    BOOL CDragEdit::DrawCaretByCursor()
    {
        int nLine, nPos;
        GetLinePosByCursor(nLine,nPos);
        SetCaretPos(GetPosFromLinePos(nLine,nPos));
        return TRUE;
    }//test if (nLine,Pos) is within (nLine1,nPos1)~(nLine2,nPos2)
    static int LinePosInRange(int nLine, int nPos,
                               int nLine1, int nPos1,
                               int nLine2, int nPos2)
    {
        if (nLine1==nLine2) {//single line selection 
            if (nLine<nLine1) return DE_BEFORESEL;
            if (nLine>nLine1) return DE_AFTERSEL;
            //nLine==nLine1
            if (nPos<nPos1) return DE_BEFORESEL;
            if (nPos>nPos2) return DE_AFTERSEL;
        }
        else { //multi-line selection 
            if (nLine<nLine1) return DE_BEFORESEL;
            if (nLine>nLine2) return DE_AFTERSEL;
            if (nLine==nLine1 && 
                nPos<nPos1) return DE_BEFORESEL;
            if (nLine==nLine2 && 
                nPos>nPos2) return DE_AFTERSEL;
        }
        return DE_INSEL;
    }//return TRUE, if cursor is within the selection 
    BOOL CDragEdit::IsInSelRange()
    {
        int nLine1, nPos1, nLine2, nPos2;
        GetCurRange(nLine1,nPos1,nLine2,nPos2);
        if (nLine1==nLine2 && nPos1==nPos2) //no selection 
            return FALSE;    int nLine, nPos;
        if (!GetLinePosByCursor(nLine,nPos)) //out of selection 
            return FALSE;
        return (LinePosInRange(nLine,nPos,nLine1,nPos1,
                               nLine2,nPos2)==DE_INSEL) ? TRUE : FALSE;
    }BOOL CDragEdit::_GetSelText(CString& str)
    {
        int nLine1, nPos1, nLine2, nPos2;
        GetCurRange(nLine1,nPos1,nLine2,nPos2);
        ASSERT(nLine1>=0 && nPos1>=0 && nLine2>=0 && nPos2>=0);
        char szBuf[MAXLINELEN];
        int nLen;
        //single-line selection
        if (nLine1==nLine2) {
            nLen=GetLine(nLine1,szBuf,sizeof(szBuf));
            szBuf[nLen]='\0';
            szBuf[nPos2]='\0';
            str=szBuf+nPos1;
            return TRUE;
        }
        //multi-line section
        nLen=GetLine(nLine1,szBuf,sizeof(szBuf));
        szBuf[nLen]='\0';
        str=szBuf+nPos1;
        for (int i=nLine1+1; i<nLine2; i++) {
            str+="\r\n";
            nLen=GetLine(i,szBuf,sizeof(szBuf));
            szBuf[nLen]='\0';
            str+=szBuf;
        }
        str+="\r\n";
        nLen=GetLine(nLine2,szBuf,sizeof(szBuf));
        szBuf[nLen]='\0';
        szBuf[nPos2]='\0';
        str+=szBuf;
        return TRUE;
    }void CDragEdit::OnLButtonDown(UINT nFlags, CPoint point) 
    {
        if (!EnableDrag()) {
            CDragEditBase::OnLButtonDown(nFlags, point);
            return;
        }    if (IsInSelRange()) {
            //get selected text
            CString str;
            if (!_GetSelText(str)) {
                CDragEditBase::OnLButtonDown(nFlags, point);
                return;
            }
            int nLine1, nPos1, nLine2, nPos2;
            GetCurRange(nLine1,nPos1,nLine2,nPos2);
            //make a copy of selected text to a global memory
            HGLOBAL hData=GlobalAlloc(GHND|GMEM_SHARE,strlen(str)+1);
            strcpy((LPSTR)GlobalLock(hData),str);
            GlobalUnlock(hData);
            ms_dropSource.CacheGlobalData(CF_TEXT,hData);        //defined dragging area
            CRect   rc(point.x-5, point.y-5, point.x+5, point.y+5);
            //It seems it is a MFC's bug that MFC will set capture to AfxGetMainWnd()
            //and use its coordinate to test the lpRectStartDrag.
            //So, we need to first translate the rc's coordinate.
            MapWindowPoints(AfxGetMainWnd(),&rc);        //start dragging
            ms_bDropEqualDrag=FALSE;
            ms_bInDragging=TRUE;
            DROPEFFECT dwEffect=ms_dropSource.DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE,&rc);
            ms_bInDragging=FALSE;
            if (dwEffect & (DROPEFFECT_MOVE | DROPEFFECT_COPY)) {
                if (dwEffect & DROPEFFECT_MOVE) {
                    if (ms_bDropEqualDrag) {
                        //If drag source equal to drop target and user want to
                        //move string
                        ms_bDropEqualDrag=FALSE;
                        int nSel=LinePosInRange(ms_nDropPtLine,ms_nDropPtPos,
                                                 nLine1,nPos1,nLine2,nPos2);
                        //we don't allow the string be moved into selection area
                        if (nSel==DE_INSEL)
                            return;
                        else {
                            if (nSel==DE_AFTERSEL) {
                                //If user want to move the string back,
                                //we need to adjust the ms_nDropPtLine 
                                //and ms_nDropPtPos
                                int nChar=_LinePosToChar(ms_nDropPtLine,ms_nDropPtPos);
                                nChar-=str.GetLength();
                                //delet selected string first
                                ReplaceSel("",TRUE);
                                _CharToLinePos(nChar,&ms_nDropPtLine,&ms_nDropPtPos);
                                //set new insert point
                                SetCaret(ms_nDropPtLine,ms_nDropPtPos);
                            }
                            else {
                                //delet selected string first
                                ReplaceSel("",TRUE);
                                //set new insert point
                                SetCaret(ms_nDropPtLine,ms_nDropPtPos);
                            }
                            //insert dragged string and sel. it
                            int nBeg, nEnd;
                            GetSel(nBeg,nEnd);        
                            nEnd+=str.GetLength();
                            ReplaceSel(str,TRUE);
                            SetSel(nBeg,nEnd);
                        }
                    }
                    else
                        ReplaceSel("",TRUE);
                }
                ms_bDropEqualDrag=FALSE;
                return;
            }
            ms_bDropEqualDrag=FALSE;
            //If user does not want to drag string, we reset the caret pos.
        SetCaretByCursor();
            return;
        }
    CDragEditBase::OnLButtonDown(nFlags, point);
    }
      

  3.   


    BOOL CDragEdit::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
    {
        if (EnableDrag()) {
            if (IsInSelRange()) {
                //if the cursor is over a selection 
                //we will change the cursor shape to a arrow type
                //It means user can drag it.
                ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
                return FALSE;
            }        
        }
        //Otherwise, we keep the cursor shape as its original type
    return CDragEditBase::OnSetCursor(pWnd, nHitTest, message);
    }
    void CDragEdit::OnDestroy()
    {
    if(ms_bDragInit)
    ms_dropTarget.Revoke();
    CDragEditBase::OnDestroy();
    }/*************************************************************
    CDEDropTarget
    **************************************************************/
    BOOL CDEDropTarget::Register(CDragEdit* pEdit)
    {
        ms_pEditCtl=pEdit;
        return COleDropTarget::Register(pEdit);
    }DROPEFFECT CDEDropTarget::OnDragScroll(CWnd* pWnd, DWORD dwKeyState, CPoint point)
    {
        ASSERT(ms_pEditCtl);
    TRACE0("....DragScroll....\n");    //if pWnd is kind of CView, we let COleDropTarget to handle it
    if (pWnd->IsKindOf(RUNTIME_CLASS(CView)))
    return COleDropTarget::OnDragScroll(pWnd,dwKeyState,point);
    TRACE0("....DragScroll(1)....\n");    if (!ms_bBeginDrop)
            return DROPEFFECT_NONE; TRACE0("....DragScroll(2)....\n");
        CRect rectClient;
    ms_pEditCtl->GetClientRect(&rectClient);
    CRect rect = rectClient;
        //nScrollInset is a COleDropTarget's static member variable
        rect.InflateRect(-nScrollInset, /*-nScrollInset*/0);
    // hit-test against inset region
    if (rectClient.PtInRect(point) && !rect.PtInRect(point)) {
            UINT        uMsg;
            int         nCode;
            CScrollBar* pScrollBar=NULL;        
    // determine which way to scroll along both X & Y axis
            if (point.x<rect.left) {
                pScrollBar=ms_pEditCtl->GetScrollBarCtrl(SB_HORZ);
                uMsg=WM_HSCROLL;
    nCode=SB_LINELEFT;
            }
            else if (point.x>=rect.right) {
                pScrollBar=ms_pEditCtl->GetScrollBarCtrl(SB_HORZ);
                uMsg=WM_HSCROLL;
    nCode=SB_LINERIGHT;
            }
            if (point.y<rect.top) {
                pScrollBar=ms_pEditCtl->GetScrollBarCtrl(SB_VERT);
                uMsg=WM_VSCROLL;
    nCode=SB_LINEUP;
            }
            else if (point.y>=rect.bottom) {
    pScrollBar=ms_pEditCtl->GetScrollBarCtrl(SB_VERT);
                uMsg=WM_VSCROLL;
    nCode=SB_LINEDOWN;
            }        LRESULT l=ms_pEditCtl->SendMessage(uMsg,MAKEWPARAM(nCode,0),
                (LPARAM)(pScrollBar ? pScrollBar->GetSafeHwnd() : NULL));        ms_pEditCtl->DrawCaretByCursor(); TRACE0("....DragScroll(10)....\n");
            if (dwKeyState & MK_CONTROL)
                return DROPEFFECT_SCROLL | DROPEFFECT_COPY;
            else
                return DROPEFFECT_SCROLL | DROPEFFECT_MOVE;
        }
    TRACE0("....DragScroll(11)....\n");
        return DROPEFFECT_NONE;
    }DROPEFFECT CDEDropTarget::OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, 
                                          DWORD dwKeyState, CPoint point)
    {
    TRACE0("Start Dragging(0)....\n");
        ASSERT(ms_pEditCtl);    if (!ms_pEditCtl->EnableDrop() || 
            !pDataObject->IsDataAvailable(CF_TEXT))
            return DROPEFFECT_NONE;    DROPEFFECT dwEffect;
        
        if (dwKeyState & MK_CONTROL)
            dwEffect=DROPEFFECT_COPY;
        else
            dwEffect=DROPEFFECT_MOVE;    ms_bBeginDrop=TRUE;    //we set focus to current window such that the caret will be shown
        ms_pEditCtl->SetFocus(); TRACE0("Start Dragging(1)....\n");
        return dwEffect;
    }void CDEDropTarget::OnDragLeave(CWnd* pWnd)
    {
        ASSERT(ms_pEditCtl); TRACE0("Leaved....\n");
        ms_bBeginDrop=FALSE;
    }DROPEFFECT CDEDropTarget::OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, 
                                         DWORD dwKeyState, CPoint point)
    {
        ASSERT(ms_pEditCtl);
    TRACE0(" .... Dragging(1)....\n");    if (!ms_bBeginDrop)
            return DROPEFFECT_NONE;    DROPEFFECT dwEffect;
        
        if (dwKeyState & MK_CONTROL)
            dwEffect=DROPEFFECT_COPY;
        else
            dwEffect=DROPEFFECT_MOVE;    ms_pEditCtl->DrawCaretByCursor();
    TRACE0(" .... Dragging(2)....\n");
        return dwEffect;
    }BOOL CDEDropTarget::OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
                               DROPEFFECT dropEffect, CPoint point)
    {
        ASSERT(ms_pEditCtl); TRACE0("Dropped....\n");
        if (!ms_bBeginDrop)
            return FALSE;    if (ms_pEditCtl->IsInDragging() &&
            ms_pEditCtl->IsInSelRange())
            return DROPEFFECT_NONE;    HGLOBAL hData=pDataObject->GetGlobalData(CF_TEXT);
        if (!hData) {
            TRACE("Fail in getting data\n");
            return FALSE;
        }
        LPCSTR lpcszData=(LPCSTR)GlobalLock(hData);
        if ((dropEffect & DROPEFFECT_MOVE) &&
            ms_pEditCtl->IsInDragging()) {
            //If the drag window equal to drop window and
            //user want to move string, we let drag source
            //to move string by itself
            ms_pEditCtl->SetDropEqualDrag(TRUE);
            int nLine, nPos;
            ms_pEditCtl->GetLinePosByCursor(nLine,nPos);
            ms_pEditCtl->SetDropPos(nLine,nPos);
        }
        else {
            //set dropped point
            ms_pEditCtl->SetCaretByCursor();
            //insert string and select the inserted string
            int nBeg, nEnd;
            ms_pEditCtl->GetSel(nBeg,nEnd);        
            nEnd+=strlen(lpcszData);
            ms_pEditCtl->ReplaceSel(lpcszData,TRUE);
            ms_pEditCtl->SetSel(nBeg,nEnd);
        }
        GlobalUnlock(hData);
        return TRUE;
    }