15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Drag & Drop support with CTreeCtrl

Pete Silvestre -- psilvest@village.ios.com
Thursday, January 25, 1996

I'm trying to add support for drag and drop between a Ctreectrl and
a Clistctrl on the same window.  Just to get my feet wet I took
a look around on the both the MSDN & VC++ 4.0 CD's to see what samples
were available.  I only found one that used MFC,  mfctree.  It doesnt
seem to operate correctly - I can drag a tree item but no image 
appears while it is being dragged and the code to do this seems to
be present (it also required a minor change to compile under 4.0).  

I'm having the same problem when I try similar code in my app (ie: 
there is no drag image).  Does anybody have or know where I can find
a simple example of code like this.  It could be for either the 95 tree
or list control.  FYI, this MFC 4.0, VC++ 4.0 under NT 3.51.  TIA...




Mickey Williams -- 75460.2102@compuserve.com
Sunday, January 28, 1996

Pete Silvestre wrote:
> I'm trying to add support for drag and drop between a Ctreectrl and
> a Clistctrl on the same window.  
> ...
>   Does anybody have or know where I can find
> a simple example of code like this.  It could be for either the 95 tree
> or list control.  FYI, this MFC 4.0, VC++ 4.0 under NT 3.51.  TIA...

The code for either is similar, but not identical, so I'll give you both -
you would think that functions like GetImageRect would have the
same signatures, but that's not the case. Anyway, merging the two
is left as an excersize to the reader - hope this helps.
---
Mickey

---------CTreeCtrl drag and drop -----------
// Handlers for TVN_BEGINDRAG, WM_MOUSEMOVE, and
// WM_LBUTTONUP

//The image list is 32 pixels wide, and image 3 is used for all the dragable
items.
// There are three member variables to handle dnd:
// HTREEITEM m_hDragItem - the item being dragged
// HTREEITEM m_hDragTarget - the item being dropped on
// BOOL m_fIsDragging - TRUE if a drag is in progress

void CTreeDispDlg::OnBegindragTree(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
    // In this tree, root nodes aren't allowed to move.
    if(m_tree.GetParentItem(pNMTreeView->itemNew.hItem) != NULL)
    {
        m_hDragItem = pNMTreeView->itemNew.hItem;
        CImageList* pDragImage;
        pDragImage = m_tree.CreateDragImage( m_hDragItem );
        ASSERT( pDragImage );
        // The next few lines calculate the position of the cursor rel to
        // the image. A crude bu simpler approach is to use CPoint(0,0)
        // as the cursor point in BeginDrag. 
        CRect   rcDrag;
        CPoint  ptCursor;
        m_tree.GetItemRect( m_hDragItem, rcDrag, TRUE );
        rcDrag.left -= 32;  // Adjust by width of image
        GetCursorPos( &ptCursor );
        m_tree.ScreenToClient( &ptCursor );
        CPoint ptDrag( ptCursor - rcDrag.TopLeft() );
        pDragImage->BeginDrag( 0, ptDrag );
        pDragImage->DragEnter( &m_tree, pNMTreeView->ptDrag );
        SetCapture();
        m_fIsDragging = TRUE;
    }
    *pResult = 0;
}

void CTreeDispDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
    if( m_fIsDragging == TRUE )
    {
        CPoint ptTree(point);
        MapWindowPoints( &m_tree, &ptTree, 1 );
        CImageList::DragMove( ptTree );

        UINT    uHitTest = TVHT_ONITEM;
        m_hDragTarget = m_tree.HitTest( ptTree, &uHitTest );
    }
    CDialog::OnMouseMove(nFlags, point);
}

void CTreeDispDlg::OnLButtonUp(UINT nFlags, CPoint point) 
{
    if( m_fIsDragging == TRUE )
    {
        CImageList::DragLeave( &m_tree );
        CImageList::EndDrag();
        ReleaseCapture();
        m_fIsDragging = FALSE;
        // Test for valid drop target.
        if((m_hDragTarget != NULL)&&(m_hDragTarget != m_hDragItem))
        {
            // Create a copy of the drag item.
            HTREEITEM   hParent;
            hParent = m_tree.GetParentItem( m_hDragTarget );
            CString szLabel = m_tree.GetItemText( m_hDragItem );
            if( hParent != NULL )
                m_tree.InsertItem( szLabel, 3, 3, hParent,
                                   m_hDragTarget );
            else
                m_tree.InsertItem( szLabel, 3, 3, m_hDragTarget,
                                   TVI_FIRST );
            // Remove the existing copy of the drag item.
            m_tree.DeleteItem( m_hDragItem );
        }
    }
    else
        CDialog::OnLButtonUp(nFlags, point);
}

---- A list view drag and drop -----------

// This list view uses image and text callbacks, so it isn't completely
// interchangable with the tree-view. On the other hand, it does show
// how the basic dnd works.
// There are three member variables here also:
// int m_nDragItem, m_nDragTarget; - the draggee and drop target
// BOOL m_fIsDragging; - True if a drag is in progress

void CTravelDlg::OnBegindragList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

    m_nDragItem = pNMListView->iItem;
    CImageList* pDragImage;
    pDragImage = m_listCtrl.CreateDragImage( m_nDragItem, &pNMListView->ptAction
);
    ASSERT( pDragImage );

    CRect   rcDrag;
    CPoint  ptCursor;
    m_listCtrl.GetItemRect( m_nDragItem, rcDrag, LVIR_ICON );
    GetCursorPos( &ptCursor );
    m_listCtrl.ScreenToClient( &ptCursor );
    CPoint ptDrag( ptCursor - rcDrag.TopLeft() );

    pDragImage->BeginDrag( 0, ptDrag );
    pDragImage->DragEnter( &m_listCtrl, pNMListView->ptAction );
    SetCapture();
    m_fIsDragging = TRUE;

    *pResult = 0;
}

void CTravelDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
    if( m_fIsDragging == TRUE )
    {
        CPoint ptList(point);
        MapWindowPoints( &m_listCtrl, &ptList, 1 );
        CImageList::DragMove( ptList );
        UINT    uHitTest = LVHT_ONITEM;
        m_nDragTarget = m_listCtrl.HitTest( ptList, &uHitTest );
    }
    CDialog::OnMouseMove(nFlags, point);
}

void CTravelDlg::OnLButtonUp(UINT nFlags, CPoint point) 
{
    if( m_fIsDragging == TRUE )
    {
        CImageList::DragLeave( &m_listCtrl );
        CImageList::EndDrag();
        ReleaseCapture();
        m_fIsDragging = FALSE;
        if((m_nDragTarget != -1)&&(m_nDragTarget != m_nDragItem))
        {
            LV_ITEM theItem;
            theItem.iItem = m_nDragItem;
            theItem.iSubItem = 0;
            theItem.mask = LVIF_PARAM;
            VERIFY( m_listCtrl.GetItem( &theItem ) );

             // Obviously, this section is different for other applications....
            CHotel* pOldHotel = (CHotel*)theItem.lParam;
            ASSERT(pOldHotel);
            CHotel* pNewHotel = new CHotel(*pOldHotel);
            ASSERT(pNewHotel);
            theItem.iItem = m_nDragTarget;
            theItem.iImage = pNewHotel->m_nRank;
            theItem.mask |= (LVIF_TEXT | LVIF_IMAGE);
            theItem.pszText = LPSTR_TEXTCALLBACK;
            theItem.cchTextMax = 40;
            theItem.lParam = (LPARAM)pNewHotel;
            VERIFY( m_listCtrl.InsertItem(&theItem) != -1 );
            m_listCtrl.SetItemText( m_nDragTarget, 1, LPSTR_TEXTCALLBACK );
            m_listCtrl.SetItemText( m_nDragTarget, 2, LPSTR_TEXTCALLBACK );

            if( m_nDragTarget < m_nDragItem )
                m_nDragItem++;

            VERIFY( m_listCtrl.DeleteItem( m_nDragItem ));
        }
    }
    else
        CDialog::OnLButtonUp(nFlags, point);
}





| Вернуться в корень Архива |