拖拽功能的实现是一个全局的功能实现,也就是没有进程之隔,是一个类似windows的文件拖拽管理和打开的功能。而下面说记录的是关于任意内容的全局拖拽的实现细节。关于相关函数和对象的具体描述可以直接MSDN查看,这里就不对其进行详细的简介。
大体的实现可以分为两个主要的部分:
1. 被拖拽对象中添加COleDataSource,以处理被拖拽对象
2. 在拖拽目标中添加COleDropTarget, 以处理拖拽目标接受拖拽的相关事件
下面是具体的代码示例,这个示例的具体功能实现的是把CTreeCtrl中的一个item所关联的数据拖拽到指定的CView类中,类似与文件的拖拽打开。
1. 关于被拖拽对象CTreeCtrl中的相关代码实现:
1.1. 首先在CTreeCtrl的扩展类中添加COleDataSource对象,我这里添加的是COleDataSource类型的指针。
class CDataViewTree : public CTreeCtrl
{
private:
COleDataSource* m_dropSource;
... ...
//这是开始拖拽的消息处理函数
public:
afx_msg void OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult);
... ...
};
1.2. 在消息映射表中添加消息映射,处理开始拖拽的消息。
BEGIN_MESSAGE_MAP(CDataViewTree, CTreeCtrl)
ON_NOTIFY_REFLECT(TVN_BEGINDRAG, &CDataViewTree::OnTvnBegindrag)
END_MESSAGE_MAP()
1.3. 具体的实现部分都在OnTvnBegingdrag()函数中。
void CDataViewTree::OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
char* hgMem = NULL, *htmpMem = NULL;
HTREEITEM hItem = GetSelectedItem();
CString dataBuf_dataName, dataBuf_dataID;
int typeIndex, ctrlType, bufSize;
//可以修改成多项同时拖拽
if (hItem != NULL && GetChildItem(hItem) == NULL)
{
//这里我的每个item关联的是一个变量,所用数据包括了变量的名字,ID, 类型
dataBuf_dataName = GetItemText(hItem);
dataBuf_dataID = GetItemID(hItem);
typeIndex = GetItemTypeIndex(hItem);
bufSize = 4 + 32*2 + dataBuf_dataName.GetLength()*2+2;
m_dropSource = new COleDataSource;
//开辟全局缓存,用来保存被拖放对象的相关数据,这里一个大小
hgMem = (char*)GlobalAlloc(GPTR, bufSize);
htmpMem = (char*)GlobalLock((HGLOBAL)hgMem);
ASSERT(htmpMem != NULL);
ZeroMemory(htmpMem, bufSize);
// 缓存中数据的保存格式可以根据自己的需求来定,注意要便于缓存的读取
*((int*)htmpMem) = typeIndex;
lstrcpy((TCHAR*)(htmpMem + 4), dataBuf_dataID);
lstrcpy((TCHAR*)(htmpMem + 68), dataBuf_dataName);
// 缓存关联
m_dropSource->Empty();
m_dropSource->CacheGlobalData(CF_TEXT, (HGLOBAL)htmpMem);
// 开始数据拖拽,函数会在拖拽结束后返回
DROPEFFECT dropEffect = m_dropSource->DoDragDrop();
// 空间的解锁和释放
GlobalUnlock((HGLOBAL)hgMem);
GlobalFree((HGLOBAL)hgMem);
delete m_dropSource;
m_dropSource = NULL;
}
}
2. 关于拖拽目标中的相关代码实现
2.1. 拖拽接收目标中添加COleDropTarget对象。并添加相关的处理函数,其中包括了OnDragEnter(), OnDragOver(), OnDragLeave(), 和OnDrop()函数,这几个函数都是虚函数,你可以使用MFC类向导添加,也可以自己手动添加。
class CWindowView : public CView
{
private:
COleDropTarget m_oleTarget;
... ...
public:
virtual DROPEFFECT OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
virtual void OnDragLeave();
virtual DROPEFFECT OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
virtual BOOL OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);
... ...
}
2.2. 在创建CView时,一定要调用COleDropTarget对象的Register()方法,注册该窗口,使窗口可以接受拖拽。
int CWindowView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// 注册,
m_oleTarget.Register(this);
return 0;
}
2.3. 相关的虚函数的具体实现
DROPEFFECT CWindowView::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
// 返回值可能决定图标显示效果
return DROPEFFECT_MOVE;
}
void CGeneralUI_CreateWindowView::OnDragLeave()
{
CView::OnDragLeave();
}
DROPEFFECT CGeneralUI_CreateWindowView::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
return DROPEFFECT_MOVE;
}
BOOL CGeneralUI_CreateWindowView::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
{
// TODO: 在此添加专用代码和/或调用基类
HGLOBAL hgMem = NULL;
char* htmpMem = NULL;
CString dataBuf_dataName, dataBuf_dataID;
int typeIndex= 6;
if (pDataObject->IsDataAvailable(CF_TEXT))
{
hgMem = pDataObject->GetGlobalData(CF_TEXT);
htmpMem = (char*)GlobalLock(hgMem);
if (htmpMem != NULL)
{
typeIndex = *(int*)htmpMem;
dataBuf_dataID.Format(L"%s", (TCHAR*)(htmpMem + 4));
dataBuf_dataName.Format(L"%s", (TCHAR*)(htmpMem + 68));
CWnd* onCtrlPtr = CheckCurSelCtrl(point);
// 获取到了数据,根据自己的要求做你自己的相关操作
AfxMessageBox(dataBuf_dataName + L" " + dataBuf_dataID);
}
}
GlobalUnlock(hgMem);
return TRUE;
}
以上就是拖拽功能实现的全部代码,希望可以帮到大家。代码的优化还请大家多给点意见。
关于参考资料我就不进行罗列了。