WEB开发网
开发学院软件开发VC 树型控件拖动的完美实现 阅读

树型控件拖动的完美实现

 2006-07-23 11:20:32 来源:WEB开发网   
核心提示: 设置一个定时器,当鼠标在拖动过程中停止在某个节点上时,树型控件拖动的完美实现(3),定时器被启动,再设置一变量保存当前的鼠标位置,下面是实现的源代码// XTreeCtrl.h……protected:UINTm_TimerTicks;//处理滚动的定时器所经

设置一个定时器,当鼠标在拖动过程中停止在某个节点上时,定时器被启动,再设置一变量保存当前的鼠标位置。

下面是实现的源代码

// XTreeCtrl.h
……
protected:
  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;   //接受拖动的标签
……
// XTreeCtrl.cpp
……
#define  DRAG_DELAY  60
……
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);
}

通过上面的代码我们就实现了树型控件的拖动操作。

示例程序在 VC6+Windows2000 上调试通过。

上一页  1 2 3 

Tags:控件 拖动 完美

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接