The Wayback Machine - https://web.archive.org/web/20111028061803/http://www.codeguru.com/cpp/controls/treeview/dragdrop/article.php/c707/

    Drag and drop




    "An operation in which the end user uses the mouse or other pointing device to move data to another location in the same window or another window". This is right off the glossary in the VC++ help files. Note that this statement says move data but drag and drop is commonly understood to encompass copy data as well. In this section we will cover drag and drop to move data within the same window - the tree view control..

    Step 0: Make sure that the control style supports drag and drop

    If the control has the TVS_DISABLEDRAGDROP style then the TVN_BEGINDRAG notification is not sent. So make sure that the control does not have the TVS_DISABLEDRAGDROP style.

    Step 1: Declare member variables

    Add member variables to the CTreeCtrl derived class to track whether drag and drop is in progress and the handle of the drag item and the drop location. The m_pDragImage variable holds the image list used during the drag and drop operation.
     
    protected:
    	CImageList*	m_pDragImage;
    	BOOL		m_bLDragging;
    	HTREEITEM	m_hitemDrag,m_hitemDrop;

    Step 2: Add handler for TVN_BEGINDRAG

    You can use the class wizard to add a handler for the TVN_BEGINDRAG notification. The handler function has been named OnBeginDrag() in the listing below. The code first sets up the member variables. It then creates an image that will drag across the screen as the mouse moves. CreateDragImage() is a member of the CTreeView class and it creates an image consisting of the item image and the label text.

    BeginDrag() function is called with an argument of zero and a point. The zero indicates the first image, which is the only image in the image list. The value we use for the second argument causes the image to be drawn to the right lower side of the cursor. You may want to experiment with this value if the image position does not suit your taste.

    We call the DragEnter() to display the drag image. The first argument is NULL so that the drag image will be visible even if the mouse is dragged outside the treeview control.
     

    void CTreeCtrlX::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) 
    {
    	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
    	*pResult = 0;
    
    	m_hitemDrag = pNMTreeView->itemNew.hItem;
    	m_hitemDrop = NULL;
    
    	m_pDragImage = CreateDragImage(m_hitemDrag);  // get the image list for dragging
    	// CreateDragImage() returns NULL if no image list
    	// associated with the tree view control
    	if( !m_pDragImage )
    		return;
    
    	m_bLDragging = TRUE;
    	m_pDragImage->BeginDrag(0, CPoint(-15,-15));
    	POINT pt = pNMTreeView->ptDrag;
    	ClientToScreen( &pt );
    	m_pDragImage->DragEnter(NULL, pt);
    	SetCapture();
    }

    Step 3: Add handler for WM_MOUSEMOVE to update drag image

    In this handler we basically update the position of the drag image and update the drop position. The DragMove() function moves the drag image. We then update the drop target if the mouse is over a tree view item. Note the calls to DragShowNolock(). The first call hides the drag image and allows the tree view control to be updated. The second calls displays the drag image again. We can also use a combination of DragLeave() and DragEnter() but I found that using these functions causes some redraw problems.
     
    void CTreeCtrlX::OnMouseMove(UINT nFlags, CPoint point) 
    {
    	HTREEITEM	hitem;
    	UINT		flags;
    
    	if (m_bLDragging)
    	{
    		POINT pt = point;
    		ClientToScreen( &pt );
    		CImageList::DragMove(pt);
    		if ((hitem = HitTest(point, &flags)) != NULL)
    		{
    			CImageList::DragShowNolock(FALSE);
    			SelectDropTarget(hitem);
    			m_hitemDrop = hitem;
    			CImageList::DragShowNolock(TRUE);
    		}
    	}
    	
    	CTreeCtrl::OnMouseMove(nFlags, point);
    }

    Step 4: Finally add handler for WM_LBUTTONUP

    It is in the WM_LBUTTONUP handler that we complete the drag and drop process. We first determine whether a drag - drop operation was in progress. This is a good place to delete the image list object we created by calling CreateDragImage() in OnBeginDrag() function. Before moving the branch we make sure that the move is valid. The call to Expand() is normally not necessary, however, if we implement dynamic loading, wherein the items are loaded only after the parent is expanded then this call is important.
     
    void CTreeCtrlX::OnLButtonUp(UINT nFlags, CPoint point) 
    {
    	CTreeCtrl::OnLButtonUp(nFlags, point);
    
    	if (m_bLDragging)
    	{
    		m_bLDragging = FALSE;
    		CImageList::DragLeave(this);
    		CImageList::EndDrag();
    		ReleaseCapture();
    
    		delete m_pDragImage;
    
    		// Remove drop target highlighting
    		SelectDropTarget(NULL);
    
    		if( m_hitemDrag == m_hitemDrop )
    			return;
    
    		// If Drag item is an ancestor of Drop item then return
    		HTREEITEM htiParent = m_hitemDrop;
    		while( (htiParent = GetParentItem( htiParent )) != NULL )
    		{
    			if( htiParent == m_hitemDrag ) return;
    		}
    
    		Expand( m_hitemDrop, TVE_EXPAND ) ;
    
    		HTREEITEM htiNew = CopyBranch( m_hitemDrag, m_hitemDrop, TVI_LAST );
    		DeleteItem(m_hitemDrag);
    		SelectItem( htiNew );
    	}
    
    }

    IT Offers