這邊需使用到CImageList來進行,D&D的圖示繪製。
由於CTreeCtrl有提供接收D&D的訊息事件,TVN_BEGINDRAG。
新增的方式為,選擇於類別檢視內的CTreeCtrl衍伸類別,之後選擇屬性視窗,點選訊息,之後新增TVN_GEGINDRAG就可以了。
這邊會需要用到幾個data member,所以先宣告好。
Header:
.....
protected:
CImageList *m_pDragImage;
HTREEITEM m_hDragItem;
HTREEITEM m_hDropItem;
BOOL m_IsLDragging;
.....
在建立好OnTvnBegindrag()後,就可以在裡面實作按下滑鼠左鍵的行為:
void CDSTreeCtrl::OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: 在此加入控制項告知處理常式程式碼
*pResult = 0;
this->m_hDragItem = pNMTreeView->itemNew.hItem;
this->m_pDragImage = this->CreateDragImage(this->m_hDragItem);
if ( !this->m_pDragImage ) {
return; };
this->m_IsLDragging = TRUE;
this->m_pDragImage->BeginDrag(0, CPoint(-15, -15)); //0 = current used image. Because of this item just has one image.
//Under cursor, (-15, -15).
POINT pt = pNMTreeView->ptDrag;
ClientToScreen(&pt);
this->m_pDragImage->DragEnter(NULL, pt);
this->SetCapture();
}
此時,僅有設定拖曳的時候所要顯示的圖示,所以還要處理WM_MOUSEMOVE的事件。這個訊息一樣可以透過上述方式來新增。
void CDSTreeCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此加入您的訊息處理常式程式碼和 (或) 呼叫預設值
HTREEITEM hItem = NULL;
UINT uFlag = 0;
if ( this->m_IsLDragging )
{
POINT pt = point;
ClientToScreen(&pt);
CImageList::DragMove(pt);
if ( NULL != (hItem = this->HitTest(point, &uFlag)) )
{
CImageList::DragShowNolock(FALSE);
this->SelectDropTarget(hItem);
this->m_hDropItem = hItem;
CImageList::DragShowNolock(TRUE);
} //End of if ( NULL != (hItem = this->HitTest(point, &flags)) )
} //End of if ( this->m_IsLDragging )
CTreeCtrl::OnMouseMove(nFlags, point);
}
最後就是當滑鼠左鍵釋放時,要把選擇的item移到新的位置去。這邊的作法目前僅適用於同一個Tree的item移動。
如有要移到其他位置,那就要配合SendMessage()來處理了。
void CDSTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此加入您的訊息處理常式程式碼和 (或) 呼叫預設值
if ( this->m_IsLDragging )
{
this->m_IsLDragging = FALSE;
CImageList::DragLeave(this);
CImageList::EndDrag();
::ReleaseCapture();
delete this->m_pDragImage; //MUST TO DO.
this->SelectDropTarget(NULL); //Remove drop target highlighting
if ( this->m_hDragItem == this->m_hDropItem ) {
return; };
//If Drag item is an ancestor of drop item then return
HTREEITEM hItemParent = this->m_hDropItem;
while ( NULL != (hItemParent = this->GetParentItem(hItemParent)) )
{
if ( hItemParent == this->m_hDragItem ) {
return; };
} //End of while ( NULL != (hItemParent = this->GetParentItem(hItemParent)) )
this->Expand(this->m_hDropItem, TVE_EXPAND);
//HTREEITEM hItemNew = NULL;
//hItemNew = CopyBranch(this->m_hDragItem, this->m_hDropItem, TVI_LAST);
//REF:http://www.vckbase.com/english/code/treeview/copy_item.shtml.htm
//this->DeleteItem(this->m_hDragItem);
//this->SelectItem(hItemNew);
} //End of if ( this->m_IsLDragging )
CTreeCtrl::OnLButtonUp(nFlags, point);
}
NOTE:由於TreeCtrl收到的座標原點在TreeCtrl內,所以當LButtonUp時,所得到的座標資訊,是無法用在其他的物件內。 故必須重新抓新的滑鼠座標。
處理方式有以下兩種:
1.直接用GetCursorPos()並配合ScreenToClient()來取得被當作Drop目的地的座標。
pLDragOnGLView->pTree->ClientToScreen(&pLDragOnGLView->ptMousePos);
this->m_glWindow.ScreenToClient(&pLDragOnGLView->ptMousePos);
2.將CTreeCtrl提供的point先用ClientToScreen()轉成螢幕座標,再用被當作Drop目的物件的ScreenToClient()來取得實際的座標位置。
CPoint pt;
::GetCursorPos(&pt);
this->m_glWindow.ScreenToClient(&pt);
this->m_glWindow.OnLButtonUp(pLDragOnGLView->unMouseMovementFlags, pLDragOnGLView->ptMousePos);
然後由於在OnTvnBeginDrag()時,有設定SetCapture(),所以LButtonUp的訊息會先進到CTreeCtrl內,因此如有要把拖曳的物件放到別的控制項的話,必須在另外呼叫控制項的LButtonUp。
No comments:
Post a Comment