Drag and drop between views in a splitter window | CodeGuru

Drag and drop between views in a splitter window

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 […]

Written By
CodeGuru Staff
CodeGuru Staff
Dec 11, 1998
1 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

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
Advertisement

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

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.