最近编写了一个需要用到拖放功能的软件,之前本人对其还不神了解,找了网上的一些资料但多说的不是很直接。在这里说说我的心得。
以下所说的拖放功能是急于OLE的所以在程序的初始化中确认有如下的语句:
if (!AfxOleInit())
{
return FALSE;
}
这个原因费了我很多时间啊
拖放有一个源和一个目的,所以实现的时候需要有两个主要的类:源类COleDataSource、目的类COleDropTarget。
源的实现必须从COleDataSource类派生而来,由于源和目的必须有信息的传送。所以COleDataSource提供了几种信息传送方式,这里先介绍一种OnRenderFileData(LPFORMATETC lpFormatEtc,CFile* pFile),这个函数是从COleDataSource继承下来并实现的。以下是类的源码我的一个例子传送一个文本到目的控件
class CMyDataSource : public COleDataSource
{
protected:
// Attributes
public:
// Operations
public:
public:
CString m_strGifFullPath;
virtual ~CMyDataSource();
CMyDataSource();
// Generated message map functions
protected:
virtual BOOL OnRenderFileData(LPFORMATETC,CFile*);
};
BOOL CMyDataSource::OnRenderFileData(LPFORMATETC lpFormatEtc,CFile* pFile)
{
if(lpFormatEtc->cfFormat==CF_TEXT)
{
CArchive ar(pFile, CArchive::store);
ar.WriteString(m_strGifFullPath);
ar << (BYTE)'\0'; //注意试图不要关闭ar和pFile否则目的控件就不能接受到信息
return TRUE;
}
COleDataSource::OnRenderFileData(lpFormatEtc,pFile);
return FALSE;
}
启动拖放功能,我是从ListCtrl中拖出来的所以在OnBegindragFileList事件中写代码的 , 当然也可以在其他事件中启动,如左键按下。代码如下
CMyDataSource ItemDragDrop;
ItemDragDrop.DelayRenderFileData(CF_TEXT,NULL);//执行OnRenderFileData来获取数据
ItemDragDrop.m_strGifFullPath ="要传送的内容";
int iRes = ItemDragDrop.DoDragDrop();//直到左键弹起才返回
switch(iRes)
{//完成拖放后的处理
case DROPEFFECT_MOVE:
break;
case DROPEFFECT_COPY:
break;
case DROPEFFECT_NONE:
default:
break;
}
目的接收功能实现考COleDropTarget类完成的,添加一个成员到你的视图类中如COleDropTarget m_oleDropTarget;,并在视图类的OncCreate函数中注册该成员m_oleDropTarget.Register(this);工作完成一般,下面就是具体的接收代码了。
在视图类中有下面几个虚函数需要重写(很多文章中说消息,搞不懂),
OnDrop最后放下时调用
OnDragOver在视图上时调用
OnDragEnter鼠标刚进入视图时调用
OnDragLeave鼠标离开视图时调用
下面代码主要修改OnDrop和OnDragOver函数
全部使用默认的代码是不是OnDrop怎么都不调用啊 ,呵呵我也搞了很久才懂啊
因为默认代码OnDragOver返回值是DROPEFFECT_NONE所以OnDrop就不发生了,因此必须重写函数返并返回非DROPEFFECT_NONE值,简单一点就 return DROPEFFECT_COPY;好了。这时就断点调试停下了吧。没停下我也不懂了。
OndDrop函数的代码如下
if(pDataObject->IsDataAvailable(CF_TEXT))
{
CFile *pFile = pDataObject->GetFileData(CF_TEXT); //这个时候就会去调用源的OnRenderFileData函数了
CArchive ar(pFile, CArchive::load);
CString str;
ar.ReadString(str);
ar.Close();//
delete pFile;//记得关闭和析构哦,否则就内存泄漏咯
}
return TRUE;//默认的return 不要也可以反正是执行空函数,不信就跟进去看看吧
好了这样一个拖放的过程就完成了,在读的地方设置个断点看看数据是不是传送过来了啊,有的话就恭喜恭喜了,没有就从新检查一遍吧