如何让CEdit控件支持鼠标拖拽文本

linsi 2005-10-19 12:45:22
我指的不是拖拽文件,是指的拖拽文本:包括拖拽他自己里面的文本,和拖拽其它地方的文本到它里面来。
...全文
464 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
jerry 2005-10-19
  • 打赏
  • 举报
回复

BOOL CDragEdit::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (EnableDrag()) {
if (IsInSelRange()) {
//if the cursor is over a selection mark
//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;
}
jerry 2005-10-19
  • 打赏
  • 举报
回复

//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 mark
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 mark
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 mark
BOOL CDragEdit::IsInSelRange()
{
int nLine1, nPos1, nLine2, nPos2;
GetCurRange(nLine1,nPos1,nLine2,nPos2);
if (nLine1==nLine2 && nPos1==nPos2) //no selection mark
return FALSE;

int nLine, nPos;
if (!GetLinePosByCursor(nLine,nPos)) //out of selection mark
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);
}
jerry 2005-10-19
  • 打赏
  • 举报
回复
网上有这样的类 CDragEdit



//////////////////////////////////////
//
// Author : Sam Lu
// E-mail : ysl@springsoft.com.tw
//

#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 CEdit

class 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 : ysl@springsoft.com.tw
//

#include "stdafx.h"
#include "CDragEdit.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define MAXLINELEN 2048

enum {
DE_INSEL, DE_BEFORESEL, DE_AFTERSEL
};

/////////////////////////////////////////////////////////////////////////////
// CDragEdit

CDragEdit::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;
}
linsi 2005-10-19
  • 打赏
  • 举报
回复
好的,感谢。看来处理起来挺麻烦的,呵呵~~

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧