關於MFC中任意物件的拖拽功能的實現(COleDataSource, COleDropTarget)
拖拽功能的實現是一個全域性的功能實現,也就是沒有程序之隔,是一個類似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;
}
以上就是拖拽功能實現的全部程式碼,希望可以幫到大家。程式碼的優化還請大家多給點意見。
關於參考資料我就不進行羅列了。