為了讓菜單支援拖拽,需要做:1、為菜單添加
MNS_DRAGDROP風格MENUINFO Info ;Info.cbSize = sizeof(MENUINFO) ;Info.fMask = MIM_STYLE ;Info.dwStyle= MNS_DRAGDROP ;SetMenuInfo( hMenu , &Info ) ;
註:當
WINVER>=0x500
,才能找到
NMS_DRAGDROP
和下面相關常數的定義 2、處理
WM_MENUDRAG訊息其中, wParam 指定被拖拽功能表項目的位置,lParam為菜單的控制代碼。傳回值如果是MND_CONTINUE,則菜單仍然啟用,如果滑鼠被釋放,它將被忽略!
就是說不實現拖拽功能,使用預設的處理方式!如果是MND_ENDMENU,則菜單將關閉。要實現拖拽,要返回該值! 重點在於,在WM_MENUDRAG內要啟動拖操作,這裡我使用了OLE拖-放傳輸協議,即調用 DoDragDrop : - 分配記憶體,大小是256位元組。空間的大小要根據實際情況來定!
HGLOBAL hGlobal = ::GlobalAlloc( GMEM_SHARE | GMEM_ZEROINIT , 256 ) ;
- 將需的資料儲存到分配的記憶體中,這裡我將儲存菜單的文本
LPVOID pvoid = ::GlobalLock( hGlobal ) ;LPTSTR lpstr = (LPTSTR)pvoid ;::GetMenuString( hMenu , pos , lpstr , MAX_PATH - 1 , MF_BYPOSITION ) ;::GlobalUnlock( hGlobal ) ;
註:hMenu 來自 lParam , pos 來自 wParam - 準備IDataObject、IDropSource對象
STGMEDIUM stgMedium ;memset( &stgMedium , 0 , sizeof(STGMEDIUM) ) ;stgMedium.tymed = TYMED_HGLOBAL ;stgMedium.hGlobal = hGlobal ;stgMedium.pUnkForRelease = NULL ; CMenuDataObject *pDataObj = new CMenuDataObject (&stgMedium,m_uClipboardFormat); CMenuDropSource *pDropSource = new CMenuDropSource ; pDropSource->AddRef() ;pDataObj->AddRef() ;
註:
CMenuDataObject
派生自
IDataObject ;
CMenuDropSource
派生自
IDropSource
m_uClipboardFormat
是自訂的資料格式,為了能區分出自已的資料。
m_uClipboardFormat= RegisterClipboardFormat( “MyFormat” ) ;
這裡比較麻煩的是
CMenuDataObject
和
CmenuDropSource
實現,其不
在本文的討論範圍,請參考相關資料,
MSDN
的例子等。
http://www.cppblog.com/windcsn/category/995.html
對
drag&drop
也要比較
詳細的描述。
- 調用DoDragDrop 啟動拖操作 DWORD dwEffect = 0 ;HRESULT ret = ::DoDragDrop( pDataObj , pDropSource , DROPEFFECT_MOVE , &dwEffect ); pDropSource->Release() ;pDataObj->Release() ; - 檢查傳回值,釋放資源 if( ret == DROPEFFECT_MOVE ){::GlobalFree( hGlobal ) ;return MND_ENDMENU ;}
註:如果你用
MFC
,這一切將變得很簡單
,IDataObject
和
IDataSource
都由
MFC
實現:
COleDataSource *pSource = new COleDataSource ;
pSource->CacheData( (CLIPFORMAT)m_uClipboardFormat , &stgMedium ) ;
DROPEFFECT ret = DROPEFFECT_NONE ;
ret = pSource->DoDragDrop( DROPEFFECT_MOVE ) ; 3、實現接收功能為了接收資料對象即支援“放”特性,它必須提供一個“放目標”對象。“放目標”
對象實現了介面IDropTarget,並且目標程式還必須把“放目標”對象與一個視窗聯絡在一起。因此,應用程式為了支援“放”特性,要調用OLE提供的API函數:RegisterDragDrop,當程式不再支援“放”特性,則可以調用RevokeDrapDrop函數取消。 OnCreate{… 視窗初始化RegisterDragDrop( m_hWnd , &m_DropTarget ) ;
} class CMyDropTarget : public IDropTarget ;CMyDropTarget m_DropTarget ; 因此,工作重點,就是實現 IDropTarget 。如果用MFC,可以讓CMyDropTarget派生自COleDropTarget 。CMyDropTarget實現不在本文討論範圍,請參考相關資料。