-- 作者:卷积内核
-- 发布时间:7/7/2009 4:07:00 PM
--
下面是实现的源代码 // 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); } 通过上面的代码我们就实现了树型控件的拖动操作。 [URL=http://www.vckbase.com/code/winui/tree/dragtree.zip]下载本文源代码[/URL]
|