dcsimg

Drag and drop between views in a splitter window

WEBINAR:
On-Demand

Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame


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



Comments

  • There are no comments yet. Be the first to comment!

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date