需要实现的操作方式及要求:1) 节点拖动:
   
   简单描述:将一个节点(包括它的所有子孙节点)拖动到其他位置,同时删除该节点原来所在位置。   拖动操作包括两种基本情况:   i) 设有非叶子节点x,对x的拖动操作,是指将x从原位置移走,成为非叶子节点y的儿子节点
       这种情况下,在拖动前要满足条件:x不能是y的儿子节点
       这种拖动操作的影响对象是一个节点下所有的节点,即整个一棵子树x。               上面这种拖动操作会有两种情况:        拖动后,x作为y的第一个儿子节点,如果x所辖叶子节点先于y所辖叶子节点
        拖动后,x作为y的最后一个儿子节点,如果y所辖叶子节点先于x所辖叶子节点   ii) 设有叶子节点x, 对x的拖动操作,是指将x从原位置移走,与另一个叶子节点y合并为一个叶子节点
       执行这种拖动操作后,如果x的父亲节点没有其他子女,要删除x的父亲节点,并且按照这种原则
       依次向上删除节点。       这种拖动操作实际上是为了实现叶子节点的合并
       比如树中有两个叶子节点,分别是“计算”和“机”,我们认为这是分词错误,有必要把这两个叶子节点合并为一个。
 
   无论是哪种拖动情况,在拖动后都要满足条件:       不能改变x所辖叶子节点和y所辖叶子节点的位置前后顺序关系例句如下:
s[np[ap[咬死了猎人的]np[狗]],vp[正向这里跑过来]]
s[np[ap[咬死了猎人的],np[狗]],vp[正向这里跑过来]]
s[np[ap[vp[vp[咬死了],np[猎人]],u[的]],np[狗]],vp[dp[正],vp[向这里跑过来]]]
s[np[ap[vp[vp[vp[咬死],u[了]],np[猎人]],u[的]],np[狗]],vp[dp[正],vp[向这里跑过来]]]
s[np[ap[vp[vp[vp[v[咬],v[死]],u[了]],np[猎人]],u[的]],np[狗]],vp[dp[正],vp[pp[p[向],s[这里]],vp[v[跑],v[过来]]]]]
zj[dj[np[他们/r],vp[vp[vp[到/v],np[校园/n]],vp[vp[去/v],vp[vp[玩/v],np[球/n]]]]],M[。/w]][]代表层次,在界面上操作,要满足上面的要求
请大家讨论讨论怎么实现?

解决方案 »

  1.   

    void CXTreeCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) 
    {
    NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
    *pResult = 0; //如果是无意拖曳,则放弃操作
    if( (GetTickCount() - m_dwDragStart) < DRAG_DELAY )
    return; m_hItemDragS = pNMTreeView->itemNew.hItem;
    m_hItemDragD = NULL; //得到用于拖动时显示的图象列表
    m_pDragImage = CreateDragImage( m_hItemDragS );
    if( !m_pDragImage )
    return; m_bDragging = true;
    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 CXTreeCtrl::OnMouseMove(UINT nFlags, CPoint point) 
    {
    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;
    } CTreeCtrl::OnMouseMove(nFlags, point);
    }void CXTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
    {
    CTreeCtrl::OnLButtonUp(nFlags, point); if( m_bDragging )
    {
    m_bDragging = FALSE;
    CImageList::DragLeave( this );
    CImageList::EndDrag();
    ReleaseCapture();
    delete m_pDragImage; SelectDropTarget( NULL );

    if( m_hItemDragS == m_hItemDragD )
    {
    KillTimer( m_nScrollTimerID );
    return;
    } Expand( m_hItemDragD,TVE_EXPAND ); HTREEITEM  htiParent = m_hItemDragD;
    while( (htiParent = GetParentItem(htiParent)) != NULL )
    {
    if( htiParent == m_hItemDragS )
    {
    HTREEITEM  htiNewTemp = CopyBranch( m_hItemDragS,NULL,TVI_LAST );
    HTREEITEM  htiNew = CopyBranch( htiNewTemp,m_hItemDragD,TVI_LAST );
    DeleteItem( htiNewTemp );
    SelectItem( htiNew );
    KillTimer( m_nScrollTimerID );
    return;
    }
    } HTREEITEM  htiNew = CopyBranch( m_hItemDragS,m_hItemDragD,TVI_LAST );
    DeleteItem( m_hItemDragS );
    SelectItem( htiNew );
    KillTimer( m_nScrollTimerID );
    }
    }//拷贝条目
    HTREEITEM CXTreeCtrl::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 CXTreeCtrl::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;
    }void CXTreeCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
    {
    //处理无意拖曳
    m_dwDragStart = GetTickCount();

    CTreeCtrl::OnLButtonDown(nFlags, point);
    }void CXTreeCtrl::OnTimer(UINT nIDEvent) 
    {
    //鼠标敏感节点
    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
    CTreeCtrl::OnTimer(nIDEvent);
    }