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

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

作者: 侧漏的少年 | 来源:发表于2016-11-17 16:52 被阅读0次

    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<nCount-1 ; i++ )
                        hItem = GetNextVisibleItem( hItem );
                    if( hItem )
                        SelectDropTarget( hItem );
                    m_hItemDragD = hItem;
                    CImageList::DragShowNolock ( true );
                }
            }
        }
        else
            __super::OnTimer(nIDEvent);
    }
    

    //拷贝条目

    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;
    }
    

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/glwdpttx.html