树形控件拖动效果的实现,父节点不能拖到子节点里

class CDBLayerTree : public CTreeCtrl
CDBLayerTree派生于CTreeCtrl类
CTreeCtrl派生于CWnd类,树形结构其实是一个窗口

添加消息响应函数:

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnTimer(UINT_PTR nIDEvent);
DECLARE_MESSAGE_MAP()

添加函数:

HTREEITEM CopyBranch(HTREEITEM htiBranch, HTREEITEM htiNewParent, HTREEITEM htiAfter);
HTREEITEM CopyItem(HTREEITEM hItem, HTREEITEM htiNewParent, HTREEITEM htiAfter);

添加变量:

protected://HPD20161103
UINT m_TimerTicks; //处理滚动的定时器所经过的时间
UINT m_nScrollTimerID; //处理滚动的定时器
CPoint m_HoverPoint; //鼠标位置
UINT m_nHoverTimerID; //鼠标敏感定时器
DWORD m_dwDragStart; //按下鼠标左键那一刻的时间
BOOL m_bDragging; //标识是否正在拖动过程中
CImageList* m_pDragImage; //拖动时显示的图象列表
HTREEITEM m_hItemDragS; //被拖动的标签
HTREEITEM m_hItemDragD; //接受拖动的标签
BOOL m_bIsChange;

函数的实现:
cpp文件加入宏:

#define   DRAG_DELAY   60
构造函数内:
m_bDragging = false;
void CDBLayerTree::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    //处理无意拖曳
    m_dwDragStart = GetTickCount();
    CTreeCtrl::OnLButtonDown(nFlags, point);
}
void CDBLayerTree::OnLButtonUp(UINT nFlags, CPoint point)
{
    //TODO:在此添加消息处理程序代码和/或调用默认值
    CString strF =_T(""), strT =_T("");
    __super::OnLButtonUp(nFlags, point);
    //__super是基类的意思
    
    if( m_bDragging )
    {
        m_bDragging = FALSE;
        CImageList::DragLeave( this );
        CImageList::EndDrag();
        ReleaseCapture();
        delete m_pDragImage;

        SelectDropTarget( NULL );

        if( m_hItemDragS == m_hItemDragD )
        {           
            goto label;
        }

        HTREEITEM hParentDragS = GetParentItem(m_hItemDragS);
        HTREEITEM hParentDragD = GetParentItem(m_hItemDragD);

        if(hParentDragS != hParentDragD)
        {
            goto label;
        }

        long lLayerHandleS,lLayerHandleD;
        lLayerHandleS = GetItemData(m_hItemDragS);
        lLayerHandleD = GetItemData(m_hItemDragD);

        {
            long  InitialPosition = -1;
            long  TargetPosition = -1;
            long  nCount = -1;
            HTREEITEM hNextItem;
            HTREEITEM hChildItem = GetChildItem(hParentDragS);

            while (hChildItem != NULL)
            {
                nCount++;
                hNextItem = GetNextItem(hChildItem, TVGN_NEXT);
                if(hChildItem == m_hItemDragS)
                {
                    InitialPosition = nCount;
                    break;
                }
                hChildItem = hNextItem;
            }

            nCount = -1;
            hChildItem = GetChildItem(hParentDragS);

            while (hChildItem != NULL)
            {
                nCount++;
                hNextItem = GetNextItem(hChildItem, TVGN_NEXT);
                if(hChildItem == m_hItemDragD)
                {
                    TargetPosition = nCount;
                    HTREEITEM  htiNew;
                    if( InitialPosition < TargetPosition )  //被拖动的往下拖,则显示在接受拖动的下面
                    {
                        htiNew = CopyBranch( m_hItemDragS, GetParentItem(m_hItemDragD), m_hItemDragD );
                    }
                    else         //被拖动的往上拖,则显示在接受拖动的上面
                    {
                        if( TargetPosition == 0 )  
                        {
                            htiNew = CopyBranch( m_hItemDragS, GetParentItem(m_hItemDragD), TVI_FIRST );
                        }
                        else
                        {
                            htiNew = CopyBranch( m_hItemDragS, GetParentItem(m_hItemDragD), GetPrevSiblingItem(m_hItemDragD) );
                        }
                    }

                    DeleteItem( m_hItemDragS );
                    SelectItem( htiNew );
                    KillTimer( m_nScrollTimerID );
                    return;
                }   
                hChildItem = hNextItem;
            }
        }
label:
        KillTimer( m_nScrollTimerID );
        m_hItemDragS = NULL;
        m_hItemDragD = NULL;
    }

    //CTreeCtrl::OnLButtonUp(nFlags, point);
}
void CDBLayerTree::OnMouseMove(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    HTREEITEM  hItem;
    UINT       flags;

    //检测鼠标敏感定时器是否存在,如果存在则删除,删除后再定时
    if( m_nHoverTimerID )
    {
        KillTimer( m_nHoverTimerID );
        m_nHoverTimerID = 0;
    }
    m_nHoverTimerID = SetTimer( 1,800,NULL );  //定时为 0.8 秒则自动展开
    m_HoverPoint = point;

    if( m_bDragging )
    {
        CPoint  pt = point;
        CImageList::DragMove( pt );

        //鼠标经过时高亮显示
        CImageList::DragShowNolock( false );  //避免鼠标经过时留下难看的痕迹
        if( (hItem = HitTest(point,&flags)) != NULL )
        {
            SelectDropTarget( hItem );
            m_hItemDragD = hItem;
        }
        CImageList::DragShowNolock( true );

        //当条目被拖曳到左边缘时,将条目放在根下
        CRect  rect;
        GetClientRect( &rect );
        if( point.x < rect.left + 20 )
            m_hItemDragD = NULL;

        __super::OnMouseMove(nFlags, point);
    }

    return;
}

//开始拖动的消息响应

void CDBLayerTree::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
    *pResult = 0;

    //如果是无意拖曳,则放弃操作
    if( (GetTickCount() - m_dwDragStart) < DRAG_DELAY )
    {
        smartlog<<"(GetTickCount() - m_dwDragStart) < DRAG_DELAY!";
        return;
    }
    HTREEITEM item = pNMTreeView->itemNew.hItem;

    HTREEITEM hParent = GetParentItem(item);

    if( !(hParent != NULL &&  GetParentItem(hParent) == NULL) )
    {
        smartlog<<"hParent != NULL &&  GetParentItem(hParent) == NULL!";
        return;
    }
    m_hItemDragS = item;
    m_hItemDragD = NULL;

    DWORD_PTR pData = GetItemData(m_hItemDragS);

    if( long(pData) >= 0 )
        m_bDragging = true;

    //得到用于拖动时显示的图象列表
    if( m_bDragging == TRUE )
        m_pDragImage = CreateDragImage( m_hItemDragS );
    else
        m_pDragImage = NULL;

    if( !m_pDragImage )
    {
        smartlog<<"m_pDragImage为NULL!";
        return;
    }
    m_pDragImage->BeginDrag ( 0,CPoint(8,8) );
    CPoint  pt = pNMTreeView->ptDrag;
    ClientToScreen( &pt );
    m_pDragImage->DragEnter ( this,pt );  //"this"将拖曳动作限制在该窗口
    SetCapture();

    m_nScrollTimerID = SetTimer( 2,40,NULL );
}

//定时器响应函数

void CDBLayerTree::OnTimer(UINT_PTR nIDEvent)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    //鼠标敏感节点
    if( nIDEvent == m_nHoverTimerID )
    {
        KillTimer( m_nHoverTimerID );
        m_nHoverTimerID = 0;
        HTREEITEM  trItem = 0;
        UINT  uFlag = 0;
        trItem = HitTest( m_HoverPoint, &uFlag );
        if( trItem && m_bDragging )
        {
            SelectItem( trItem );
            Expand( trItem, TVE_EXPAND );
        }
    }
    //处理拖曳过程中的滚动问题
    else if( nIDEvent == m_nScrollTimerID )
    {
        m_TimerTicks++;
        CPoint  pt;
        GetCursorPos( &pt );
        CRect  rect;
        GetClientRect( &rect );
        ClientToScreen( &rect );

        HTREEITEM  hItem = GetFirstVisibleItem();

        if( pt.y < rect.top +10 )
        {
            //向上滚动
            int  slowscroll = 6 - (rect.top + 10 - pt.y )/20;
            if( 0 == (m_TimerTicks % ((slowscroll > 0) ? slowscroll : 1)) )
            {
                CImageList::DragShowNolock ( false );
                SendMessage( WM_VSCROLL,SB_LINEUP );
                SelectDropTarget( hItem );
                m_hItemDragD = hItem;
                CImageList::DragShowNolock ( true );
            }
        }
        else if( pt.y > rect.bottom - 10 )
        {
            //向下滚动
            int  slowscroll = 6 - (pt.y - rect.bottom + 10)/20;
            if( 0 == (m_TimerTicks % ((slowscroll > 0) ? slowscroll : 1)) )
            {
                CImageList::DragShowNolock ( false );
                SendMessage( WM_VSCROLL,SB_LINEDOWN );
                int  nCount = GetVisibleCount();
                for( int i=0 ; i

//拷贝条目

HTREEITEM CDBLayerTree::CopyItem(HTREEITEM hItem, HTREEITEM htiNewParent, HTREEITEM htiAfter)
{
    TV_INSERTSTRUCT  tvstruct;
    HTREEITEM        hNewItem;
    CString          sText;

    //得到源条目的信息
    tvstruct.item.hItem = hItem;
    tvstruct.item.mask  = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
    GetItem( &tvstruct.item );
    sText = GetItemText( hItem );
    tvstruct.item.cchTextMax = sText.GetLength ();
    tvstruct.item.pszText    = sText.LockBuffer ();

    //将条目插入到合适的位置
    tvstruct.hParent         = htiNewParent;
    tvstruct.hInsertAfter    = htiAfter;
    tvstruct.item.mask       = TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXT;
    hNewItem = InsertItem( &tvstruct );
    sText.ReleaseBuffer ();

    //限制拷贝条目数据和条目状态
    SetItemData( hNewItem, GetItemData(hItem) );
    SetItemState( hNewItem, GetItemState(hItem, TVIS_STATEIMAGEMASK), TVIS_STATEIMAGEMASK );

    return hNewItem;
}
//拷贝分支
HTREEITEM CDBLayerTree::CopyBranch(HTREEITEM htiBranch, HTREEITEM htiNewParent, HTREEITEM htiAfter)
{
    HTREEITEM  hChild;
    HTREEITEM  hNewItem = CopyItem( htiBranch,htiNewParent,htiAfter );
    hChild = GetChildItem( htiBranch );

    while( hChild != NULL )
    {
        CopyBranch( hChild,hNewItem,htiAfter );
        hChild = GetNextSiblingItem( hChild );
    }

    return  hNewItem;
}

你可能感兴趣的:(树形控件拖动效果的实现,父节点不能拖到子节点里)