Environment: ******–>
Overwiew:
This code implements a drag & drop operation within an explorer style project
(splitter window with left hand treeView right hand listView).
How it works:
Both views have their own implmentation to handle drag & drop within the view.
By NOT setting “SetCapture/ReleaseCapture”, the drag item can be moved outside
the originator view to other targets. If the drag item (mouse cursor) leaves the
originators window the ON_WM_MOUSEMOVE()-handler of the target view gets control.
Because of that we have to ensure the views can access the same member variable –
we use the app-class.
YOUR APP CLASS:
Define some member variables at your app class:
public:
//Drag & Drop Member:
CImageList *cpDragImage;
BOOL cDragging;
CWnd *cpDragWnd;
CWnd *cpDropWnd;
HTREEITEM cTreeItemDrag;
HTREEITEM cTreeItemDrop;
int cListItemDragIndex;
int cListItemDropIndex;
CPoint cDropPoint; //list view needs global var to examine target
YOUR MAINFRAME CLASS:
To access the TreeCtrl from the ListCtrl we can use a small helper function
(if you define a “explorer style”-project the method “GetRightPane” is already
defined).
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;
}
YOUR TREE VIEW:
To access the member variables, it is useful to define a helper function to
easily access the app class:
CMyApp *CMyTreeView::GetApp()
{
return ( (CMyApp*)AfxGetApp() );
}//GetApp
Implement handler for the three messages
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)
Set all elements (this view can set) on begin of drag, perhaps target is the same
view, perhaps not.
void CMyTreeView::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW *pTreeView = (NM_TREEVIEW*)pNMHDR;
*pResult = 0;
//Get pointer to associated tree control:
CTreeCtrl &cTree = GetTreeCtrl();
GetApp()->cTreeItemDrag = pTreeView->itemNew.hItem;
GetApp()->cTreeItemDrop = NULL;
//Create a drag image (from the source item):
GetApp()->cpDragImage = cTree.CreateDragImage(GetApp()->cTreeItemDrag);
GetApp()->cpDragImage->BeginDrag(0, CPoint(-15,-15));
POINT pt = pTreeView->ptDrag;
ClientToScreen( &pt );
GetApp()->cpDragImage->DragEnter(NULL, pt);
//Initialize:
GetApp()->cDragging = TRUE;
GetApp()->cpDragWnd = &cTree;
GetApp()->cpDropWnd = NULL;
}//OnBegindrag
void CMyTreeView::OnMouseMove(UINT nFlags, CPoint point)
/*----------------------------------------------------------------------------s
Beschreibung:
Parameter:
Rueckgabe:
Autor/Copyright:
(c) Christopher Frank, FRG
----------------------------------------------------------------------------e*/
{
HTREEITEM hitem;
UINT flags;
//Get pointer to associated tree control:
CTreeCtrl &cTree = GetTreeCtrl();
//If dragging is active:
if ( GetApp()->cDragging )
{
POINT pt = point;
ClientToScreen( &pt );
//Move the image:
GetApp()->cpDragImage->DragMove(pt);
//Set selection on the current (possible) target:
if ( (hitem = cTree.HitTest(point, &flags)) != NULL )
{
GetApp()->cpDragImage->DragShowNolock(FALSE);
cTree.SelectDropTarget(hitem);
GetApp()->cTreeItemDrop = hitem;
GetApp()->cpDragImage->DragShowNolock(TRUE);
}
}
//Standardmethode:
CTreeView::OnMouseMove(nFlags, point);
}//OnMouseMove
void CMyTreeView::OnLButtonUp(UINT nFlags, CPoint point)
/*----------------------------------------------------------------------------s
Beschreibung:
Parameter:
Rueckgabe:
Autor/Copyright:
(c) Christopher Frank, FRG
----------------------------------------------------------------------------e*/
{
//Get pointer to associated tree control:
CTreeCtrl &cTree = GetTreeCtrl();
//Standardmethode:
CTreeView::OnLButtonUp(nFlags, point);
//If dragging is active:
if ( GetApp()->cDragging )
{
//Dragging is no longer active:
GetApp()->cDragging = FALSE;
GetApp()->cpDragImage->DragLeave(this);
GetApp()->cpDragImage->EndDrag();
delete GetApp()->cpDragImage;
//Remove drop target highlighting
cTree.SelectDropTarget(NULL);
//Examine the window dragimage is dropped:
GetApp()->cDropPoint = point;
ClientToScreen(&GetApp()->cDropPoint);
GetApp()->cpDropWnd = WindowFromPoint(GetApp()->cDropPoint);
//Select the type of drag source:
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);
}
}//OnLButtonUp
YOUR LIST VIEW:
To access the member variables, it is useful to define a helper function to easily
access the app class:
CMyApp *CMyListView::GetApp()
{
return ( (CMyApp*)AfxGetApp() );
}//GetApp
CMainFrame *CKAIView::GetFrame()
{
return ( ((CMainFrame*)GetParentFrame()) );
}
CMyTreeView *CMyListView::GetTree()
{
return ( GetFrame()->GetLeftPane() );
}
Implement handler for the three messages
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBegindrag)
Set all elements (this view can set) on begin of drag, perhaps target is the same
view, perhaps not.
void CMyListView::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
*pResult = 0;
//Zeiger auf den Tree-Control ermitteln:
CListCtrl &cList = GetListCtrl();
//set source of drag:
GetApp()->cListItemDragIndex = ((NM_LISTVIEW *)pNMHDR)->iItem;
//Create a drag image (from the source item):
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);
//Initialize:
GetApp()->cDragging = TRUE;
GetApp()->cListItemDropIndex = -1;
GetApp()->cpDragWnd = &cList;
GetApp()->cpDropWnd = NULL;
}//OnBegindrag
void CMyListView::OnMouseMove(UINT nFlags, CPoint point)
{
//If dragging is active:
if( GetApp()->cDragging )
{
POINT pt = point;
ClientToScreen(&pt);
//Move the image:
GetApp()->cpDragImage->DragMove(pt);
//Get drop window:
GetApp()->cpDragImage->DragShowNolock(FALSE);
GetApp()->cpDropWnd = WindowFromPoint(pt);
GetApp()->cpDropWnd->ScreenToClient(&pt);
GetApp()->cpDragImage->DragShowNolock(TRUE);
//Get tree:
CTreeCtrl &cTree = GetTree()->GetTreeCtrl();
//Remove drop target highlighting on the tree (immediate if the cursor
//leaves the treeView window)
cTree.SelectDropTarget(NULL);
}
//Standardmethode:
CListView::OnMouseMove(nFlags, point);
}//OnMouseMove
void CMyListView::OnLButtonUp(UINT nFlags, CPoint point)
{
//If dragging is active:
if( GetApp()->cDragging )
{
//Initialize end dragging:
GetApp()->cDragging = FALSE;
GetApp()->cpDragImage->DragLeave(GetDesktopWindow());
GetApp()->cpDragImage->EndDrag();
//GET THE WINDOW UNDER THE DROP POINT
GetApp()->cDropPoint = point;
ClientToScreen(&GetApp()->cDropPoint);
GetApp()->cpDropWnd = WindowFromPoint(GetApp()->cDropPoint);
//Cancel if source and target are same:
//Select the type of drag source:
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);
}
//Standardmethode:
CListView::OnLButtonUp(nFlags, point);
}//OnLButtonUp