在許多象資源管理器界面風格的應用程序中,很多的情況下要用到在不同的視之間的拖放操作。本文就具體給出了實現方法,望能給讀者一參考。(本文中用到的工程是左邊具有目錄樹視、右邊具有列表視)
首先,兩個視都應該有它們自己的實現函數來進行拖放操作。只要不設置"SetCapture/ReleaseCapture",被拖放的條目就能從原來的視拖放到目的視。如果被拖的條目(鼠標下的)離開了原來的視,那麼目的視的ON_WM_MOUSEMOVE()-消息就獲得了該條目的控制條件。所以我們必須保證不同的視(原來的視以及目的視)能訪問相同的成員變量,從而可以在app類裡面定義。
接下來,我們就在app類裡面定義一些成員變量:
public:
//拖放成員變量:
CImageList *cpDragImage;
BOOL cDragging;
CWnd *cpDragWnd;
CWnd *cpDropWnd;
HTREEITEM cTreeItemDrag;
HTREEITEM cTreeItemDrop;
int cListItemDragIndex;
int cListItemDropIndex;
CPoint cDropPoint;
//列表視需要一個全局變量來驗證目標的位置
好,我們現在來完成我們的主框架類:
為了能從列表視訪問目錄樹視,我們用到了一個小小的幫助函數(但是如果你在項目向導裡選擇了"資源管理器風格"的話, "GetRightPane()"就不用在定義了)
CMyListVIEw* CMainFrame::GetRightPane()
{
CWnd* pWnd = m_wndSplitter.GetPane(0, 1);
CMyListView* pView = DYNAMIC_DOWNCAST(CMyListVIEw, pWnd);
return pVIEw;
}
CMyTreeVIEw* CMainFrame::GetLeFTPane()
{
CWnd* pWnd = m_wndSplitter.GetPane(0, 0);
CMyTreeView *pTree = DYNAMIC_DOWNCAST(CMyTreeVIEw, pWnd);
return pTree;
}
現在到目錄樹視了:
為了能訪問需要的成員變量,我們還是先定義了一個幫助函數從而可以輕易的訪問我們的app類:
CMyApp *CMyTreeVIEw::GetApp()
{
return ( (CMyApp*)AfxGetApp() );
}
三個消息處理函數:
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)
把這個視所能設置的元素都設成是開始拖的狀態,而目的視也許是本身,或是別的視。
void CMyTreeVIEw::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW *pTreeView = (NM_TREEVIEW*)pNMHDR;
*pResult = 0;
//獲得指向樹型控件的指針:
CTreeCtrl &cTree = GetTreeCtrl();
GetApp()->cTreeItemDrag = pTreeVIEw->itemNew.hItem;
GetApp()->cTreeItemDrop = NULL;
//建立一個被拖的條目的圖象:
GetApp()->cpDragImage = cTree.CreateDragImage(GetApp()->cTreeItemDrag);
GetApp()->cpDragImage->BeginDrag(0, CPoint(-15,-15));
POINT pt = pTreeVIEw->ptDrag;
ClIEntToScreen( &pt );
GetApp()->cpDragImage->DragEnter(NULL, pt);
//初始化:
GetApp()->cDragging = TRUE;
GetApp()->cpDragWnd = &cTree;
GetApp()->cpDropWnd = NULL;
}
void CMyTreeVIEw::OnMouseMove(UINT nFlags, CPoint point)
{
HTREEITEM hitem;
UINT flags;
//獲得指向樹型控件的指針:
CTreeCtrl &cTree = GetTreeCtrl();
//如果是正在被拖動的話:
if ( GetApp()->cDragging )
{
POINT pt = point;
ClIEntToScreen( &pt );
//移動圖象:
GetApp()->cpDragImage->DragMove(pt);
if ( (hitem = cTree.HitTest(point, &flags)) != NULL )
{
GetApp()->cpDragImage->DragShowNolock(FALSE);
cTree.SelectDropTarget(hitem);
GetApp()->cTreeItemDrop = hitem;
GetApp()->cpDragImage->DragShowNolock(TRUE);
}
}
CTreeVIEw::OnMouseMove(nFlags, point);
}
void CMyTreeVIEw::OnLButtonUp(UINT nFlags, CPoint point)
{
//獲得指向樹型控件的指針:
CTreeCtrl &cTree = GetTreeCtrl();
CTreeVIEw::OnLButtonUp(nFlags, point);
//I如果是正在被拖動的話:
if ( GetApp()->cDragging )
{
//不再拖動了:
GetApp()->cDragging = FALSE;
GetApp()->cpDragImage->DragLeave(this);
GetApp()->cpDragImage->EndDrag();
delete GetApp()->cpDragImage;
cTree.SelectDropTarget(NULL);
//驗證被拖動的圖象已被放下:
GetApp()->cDropPoint = point;
ClIEntToScreen(&GetApp()->cDropPoint);
GetApp()->cpDropWnd = WindowFromPoint(GetApp()->cDropPoint);
//選擇拖動目的資源的類型:
if ( GetApp()->cpDragWnd->IsKindOf(RUNTIME_CLASS(CListVIEw)) )
{
AfxMessageBox("source is list vIEw", MB_OK);
}
else
if ( GetApp()->cpDragWnd->IsKindOf(RUNTIME_CLASS(CTreeVIEw)) )
{
AfxMessageBox("source is treevIEw", MB_OK);
}
else
AfxMessageBox("source is something else", MB_OK);
}
}
接下來就是到了列表視了,做法和前面的差不多:
CMyApp *CMyListVIEw::GetApp()
{
return ( (CMyApp*)AfxGetApp() );
}
CMainFrame *CKAIVIEw::GetFrame()
{
return ( ((CMainFrame*)GetParentFrame()) );
}
CMyTreeView *CMyListVIEw::GetTree()
{
return ( GetFrame()->GetLeFTPane() );
}
三個消息處理函數:
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)
把這個視所能設置的元素都設成是開始拖的狀態,而目的視也許是本身,或是別的視。
void CMyListVIEw::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
*pResult = 0;
//獲得指向列表控件的指針:
CListCtrl &cList = GetListCtrl();
//設置拖動資源:
GetApp()->cListItemDragIndex = ((NM_LISTVIEW *)pNMHDR)->iItem;
//建立一個被拖的條目的圖象:
POINT pt;
pt.x = pt.y = 8;
GetApp()->cpDragImage = cList.CreateDragImage(GetApp()->cListItemDragIndex, &pt);
GetApp()->cpDragImage->BeginDrag(0, CPoint (8, 8));
pt = ((NM_LISTVIEW *)pNMHDR)->ptAction;
ClIEntToScreen( &pt );
GetApp()->cpDragImage->DragEnter(NULL, pt);
//初始化:
GetApp()->cDragging = TRUE;
GetApp()->cListItemDropIndex = -1;
GetApp()->cpDragWnd = &cList;
GetApp()->cpDropWnd = NULL;
}
void CMyListVIEw::OnMouseMove(UINT nFlags, CPoint point)
{
//如果是正在被拖動的話
if( GetApp()->cDragging )
{
POINT pt = point;
ClIEntToScreen(&pt);
//移動圖象:
GetApp()->cpDragImage->DragMove(pt);
//獲得被放置的窗口:
GetApp()->cpDragImage->DragShowNolock(FALSE);
GetApp()->cpDropWnd = WindowFromPoint(pt);
GetApp()->cpDropWnd->ScreenToClIEnt(&pt);
GetApp()->cpDragImage->DragShowNolock(TRUE);
//獲得樹型控件:
CTreeCtrl &cTree = GetTree()->GetTreeCtrl();
cTree.SelectDropTarget(NULL);
}
CListVIEw::OnMouseMove(nFlags, point);
}
void CMyListVIEw::OnLButtonUp(UINT nFlags, CPoint point)
{
//如果是正在被拖動的話:
if( GetApp()->cDragging )
{
//結束拖動:
GetApp()->cDragging = FALSE;
GetApp()->cpDragImage->DragLeave(GetDesktopWindow());
GetApp()->cpDragImage->EndDrag();
//獲得放置點的窗口:
GetApp()->cDropPoint = point;
ClIEntToScreen(&GetApp()->cDropPoint);
GetApp()->cpDropWnd = WindowFromPoint(GetApp()->cDropPoint);
//如果目的資源是本身的話就取消:
//選擇拖動目的資源的類型:
if ( GetApp()->cpDragWnd->IsKindOf(RUNTIME_CLASS(CListVIEw)) )
{
AfxMessageBox("source is list vIEw", MB_OK);
}
else
if ( GetApp()->cpDragWnd->IsKindOf(RUNTIME_CLASS(CTreeVIEw)) )
{
AfxMessageBox("source is treevIEw", MB_OK);
}
else
AfxMessageBox("source is something else", MB_OK);
}
CListVIEw::OnLButtonUp(nFlags, point);
}
好了,到此為止,我們已經做好了所有的工作,可以實現在不同的視之間的拖動操作了。