?? ondragenter(),ondragmove(),ondrop().txt
字號:
本例的窗口對象是從CView派生的,CView類實現了OnDragEnter(),OnDragMove(),OnDrop()等成員函數,實現拖拽操作在派生類中重載這些函數就可以了。但是對于一般的窗口CWnd是沒有這些虛成員函數的。一個更加一般的做法是從COleDropTarget派生一個類,重載COleDropTarget的成員函數OnDragEnter(),OnDragMove(),OnDrop(),然后在窗口類中定義一個COleDropTarget派生類的對象,并把窗口注冊給這個對象就可以實現同樣的拖拽效果了。
剪貼板技術是由WINDOWS操作系統提供的用于進程內或進程間通信的一種機制。不光是拷貝粘貼操作需要用到剪貼板,拖拽也離不開它,并且他們將數據放到剪貼板上的一些代碼也極其相似。本例將展示給大家怎樣使用剪貼板。
剪貼板特點是:協議簡單,數據傳輸由用戶驅動。在很多不是由用戶驅動但要做很多數據通信的應用程序可以采用其他的進程間通信的方法。進程間通信詳細信息請您參見MSDN中Platform SDK的Interprocess Communication中的相應文檔。
WINDOWS系統缺省支持的8種剪貼板格式:
CF_BITMAP CF_DIB
CF_DIB
CF_ENHMETAFILE
CF_METAFILEPICT
CF_OEMTEXT
CF_TEXT
CF_UNICODETEXT
//將數據放到剪貼板上,一般要5個步驟,如下所示:
void CClipExamView::OnEditCopy()
{
// 1 創建一個新的COleDataSource對象
COleDataSource* pSource = new COleDataSource();
// 2 創建一個新的CSharedFile對象
CSharedFile sf(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT);
CString text = _T("Testing 1... 2... 3...");
// 3 將信息寫到CSharedFile對象中
sf.Write(text, text.GetLength());
HGLOBAL hMem = sf.Detach();
if (!hMem) return;
// 4 將CSharedFile中的數據內存傳遞到CacheGlobalData()中
pSource->CacheGlobalData(CF_TEXT, hMem);
// 5 用SetClipboard()將數據放置到剪貼板上
pSource->SetClipboard();
}
//除了采用上面的方法,還可以采用序列化的方式將數據寫到剪貼板上。
//采用序列化的方式將數據寫到剪貼板是很有用的,這樣可以給自己的應用程序定義一個自定義的剪貼板。
//這可以通過注冊一個自定義的剪貼板格式來實現,并且將數據序列化到CSharedFile對象中
//下面舉例說明如何將一個CObject對象序列化到剪貼板中
void SerializeToClipboard(CObject* obj,CString FormatName)
{
COleDataSource* pSource = new COleDataSource();
CSharedFile sf(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT);
UINT format=RegisterClipboardFormat(FormatName);
CArchive ar(&sf,CArchive::store);
obj->Serialize(ar);
ar.Close();
HGLOBAL hMem = sf.Detach();
if (!hMem) return;
pSource->CacheGlobalData(format, hMem);
pSource->SetClipboard();
}
//從剪貼板上讀取數據,正好與OnEditCopy相反,也是5個步驟
void CClipExamView::OnEditPaste()
{
// 1 創建一個新的COleDataObject對象
COleDataObject obj;
// 2 檢查剪貼板中數據格式是否滿足需要
if (obj.AttachClipboard())
{
if (obj.IsDataAvailable(CF_TEXT))
{
HGLOBAL hmem = obj.GetGlobalData(CF_TEXT);
CMemFile sf((BYTE*) ::GlobalLock(hmem), ::GlobalSize(hmem));
CString buffer;
// 3 將剪貼板中的數據放到CMemFile對象中
//當然你可以用其他的內存對象或者自定義的數據類型或對象
LPSTR str = buffer.GetBufferSetLength(::GlobalSize(hmem));
// 4 從CMemFile對象中讀出數據
sf.Read(str, ::GlobalSize(hmem));
::GlobalUnlock(hmem);
// 5 用數據做相關操作
TRACE("Paste received = '%s'\r\n", buffer);
}
}
}
//同樣你可以采用序列化的方式將數據從剪貼板中取出
void SerializeFromClipboard(COleDataObject* obj,CObject* cobj,CString FormatName)
{
//根據剪貼板格式的名稱取得該格式的唯一標識
//詳細信息參考API函數:RegisterClipboardFormat
UINT format=RegisterClipboardFormat(FormatName);
//判斷剪貼板數據格式
if(obj->IsDataAvailable(format))
{
//讀取剪貼板中的數據
HGLOBAL hmem=obj->GetGlobalData(format);
//創建內存文件
CMemFile sf((BYTE*)::GlobalLock(hmem),::GlobalSize(hmem));
//序列化操作
CArchive ar(sf,CArchive::Load);
cobj->Serialize(ar);
//后續清理
ar.Close();
::GlobalUnlock(hmem);
}
}
//只要對上面的代碼做少量的改動就可以實現拖拽支持。
//當一個被拖拽的對象進入一個窗口的時候,由該窗口決定是否接受該對象
//在一個拖拽操作過程中,當鼠標在一個窗口上移動的時候OnDragOver被調用
//第一個參數pDataObject表示被拖動的數據對象
//第二個參數dwKeyState表示鍵盤的狀態
//第三個參數point表示當前的鼠標的位置
//返回值用于描述是否接受拖拽,DROPEFFECT_NONE表示不接受,否則接受
DROPEFFECT CClipExamView::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
if (pDataObject->IsDataAvailable(CF_TEXT))
return DROPEFFECT_COPY; //接受拖拽
else
return DROPEFFECT_NONE; //不接受拖拽
}
//當用戶釋放鼠標時,就可以來實現真正的數據接受了
//第一個參數pDataObject表示被拖動的數據對象
//第二個參數dropEffect表示操作類型
//第三個參數point表示當前的鼠標的位置
BOOL CClipExamView::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
{
//判斷剪貼板格式是否滿足要求
if (pDataObject->IsDataAvailable(CF_TEXT))
{
//從數據對象中取出數據
HGLOBAL hmem = pDataObject->GetGlobalData(CF_TEXT);
CMemFile sf((BYTE*) ::GlobalLock(hmem), ::GlobalSize(hmem));
CString buffer;
LPSTR str = buffer.GetBufferSetLength(::GlobalSize(hmem));
sf.Read(str, ::GlobalSize(hmem));
::GlobalUnlock(hmem);
//用'buffer'中的數據做相應的處理工作
TRACE("OnDrop received = '%s'\r\n", buffer);
return TRUE;
}
return FALSE;
}
//給拖拽操作設置數據源,并且啟動拖拽操作
void CClipExamView::OnLButtonDown(UINT nFlags, CPoint point)
{
//創建一個COleDataSource,可以認為它就是一個存放將被拖放的數據對象
COleDataSource* pSource = new COleDataSource();
//創建一個CSharedFile對象
CSharedFile sf(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT);
CString text = _T("Testing 1... 2... 3...");
//將數據寫入CSharedFile對象
sf.Write(text, text.GetLength());
//取得數據對象的內存句柄,并將數據放入剪貼板
HGLOBAL hMem = sf.Detach();
if (!hMem) return;
//CacheGlobalData()的第一個參數描述放入剪貼板的數據的格式
//第2個參數描述放入剪貼板的數據的全局內存句柄
pSource->CacheGlobalData(CF_TEXT, hMem);
//啟動拖拽操作,函數DoDragDrop到拖拽操作完成才返回
//從交互上看,就是等到用戶釋放鼠標左鍵才結束操作
pSource->DoDragDrop();
//在此可以做一些清理工作,因為在這里拖拽操作已經完成,
//沒有用的內存可以釋放了
}
//使一個View成為一個Drop Target
void CClipExamView::OnInitialUpdate()
{
CView::OnInitialUpdate();
//將窗口本身注冊給一個COleDropTarget對象,一定要注意這是必不可少的
//如果你不這樣做,那么視圖窗口將不會接受拖拽操作中的對象
//也就是說這個窗口不會成為拖拽中的對象的目標窗口(Drop Target)
m_DropTarget.Register(this);
//m_DropTarget在clipexamView.h中已經聲明為COleDropTarget m_DropTarget;
}
最后值得注意兩點:
1 要確保在應用類的InitInstance()中調用AfxOleInit()
在應用程序的入口處(一般是在應用類的InitInstance()成員函數中)調用AfxOleInit()
這是用來初始化OLE庫的
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
2 確保stdafx.h中有相關包含語句,具體請您參考工程
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -