1、树控件拖动VC编程完美实现树型控件的拖动2004-07-20 17:18作者:一块三毛钱 出处:vckbase责任编辑:方舟1、基本拖动的实现当我们要拖动一个项目时,树型视图控件会给它的父窗口发送TVN_BEGINDRAG通知消息。可以在此处创建表示项目处在拖动操作中的图象,调用 CreateDragImage 函数产生一副缺省的图象,该函数创建的图象由条目图象和标签文本组成。创建了拖动图象后,调用BeginDrag 函数指定拖动图象的热点位置,然后调用 DragEnter 函数显示拖动图象。接下来处理 WM_MOUSEMOVE 消息用于更新拖动图象,我们想让移动中的图象经过某些项目时高亮度显
2、示,这可以调用 SelectDropTarget 来实现。在调用 SelectDropTarget 前,我们先调用DragShowNolock ( false ) 来隐藏图象列表,之后再调用 DragShowNolock ( true ) 来恢复图象列表的显示,这样就不会在拖动过程中留下难看的轨迹。最后我们处理WM_LBUTTONUP 消息用于完成拖动操作,在给消息中,我们需要完成结束拖动图想的显示、删除拖动图象、释放鼠标、节点的拷贝/删除等操作。在节点的拷贝/删除操作中,如果是父节点拖到子节点上,我们可以先将父节点拷到根结点下的临时节点中,再从临时结点处拷到子节点,然后将根结点下的临时节点删
3、除,这样做的目的是防止产生异常。2、处理无意拖动大家可能都有过这样的经历:在鼠标按下时不小心移动了鼠标,这时系统就认为产生了一个移动操作。如果我们不针对这种情况加以解决的话,就很容易产生误操作。下面我们就提出一个解决方法:设置时间延迟。也就是说当用户按下鼠标后必须在原位置停留一段时间,才能激活拖动操作。3、处理拖动过程中的滚动问题当我们进行拖动时,如果目的节点不可见,则需要拖动滚动条或收拢其它一些节点以使得目的节点显示出来,无疑,这会给我们带来很大的不便。下面我们就来给树型控件添加自动滚动支持。设置一个定时器,在 WM_TIMER 消息中检测鼠标的位置,如果靠近树型控件的下边缘,则使得控件向下
4、滚动。靠近上边缘则向上滚动。 滚动速度根据鼠标的位置确定。4、拖动过程中节点的智能展开这一步我们要实现的功能是在拖动过程中当鼠标停留在某个节点上一段时间后,该节点会自动展开。设置一个定时器,当鼠标在拖动过程中停止在某个节点上时,定时器被启动,再设置一变量保存当前的鼠标位置。下面是实现的源代码/ XTreeCtrl.hprotected:UINT m_TimerTicks; /处理滚动的定时器所经过的时间UINT m_nScrollTimerID; /处理滚动的定时器CPoint m_HoverPoint; /鼠标位置UINT m_nHoverTimerID; /鼠标敏感定时器DWORD m_d
5、wDragStart; /按下鼠标左键那一刻的时间BOOL m_bDragging; /标识是否正在拖动过程中CImageList* m_pDragImage; /拖动时显示的图象列表HTREEITEM m_hItemDragS; /被拖动的标签HTREEITEM m_hItemDragD; /接受拖动的标签/ XTreeCtrl.cpp#define DRAG_DELAY 60void CXTreeCtrl:OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
6、*pResult = 0;/如果是无意拖动,则放弃操作if( (GetTickCount() - m_dwDragStart) 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
7、_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_nHoverTimerI
8、D = 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:DragShowNolo
9、ck( 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(
10、 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(
11、 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_
12、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.i
13、tem.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.it
14、em.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:CopyBranc
15、h(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;v
16、oid 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;trIt
17、em = 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 = GetFirstVisibleIte
18、m();if( pt.y 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 %
19、(slowscroll 0) ? slowscroll : 1) )CImageList:DragShowNolock ( false );SendMessage( WM_VSCROLL,SB_LINEDOWN );int nCount = GetVisibleCount();for( int i=0 ; i 1000#pragma once#endif / _MSC_VER 1000class CXTreeCtrl : public CTreeCtrl/ Constructionpublic:CXTreeCtrl();/ Attributespublic:/ Operationspublic
20、:/ Overrides/ ClassWizard generated virtual function overrides/AFX_VIRTUAL(CXTreeCtrl)/AFX_VIRTUAL/ Implementationpublic:virtual CXTreeCtrl();/ Generated message map functionsprotected:UINT m_TimerTicks; /处理滚动的定时器所经过的时间UINT m_nScrollTimerID; /处理滚动的定时器CPoint m_HoverPoint; /鼠标位置UINT m_nHoverTimerID; /
21、鼠标敏感定时器DWORD m_dwDragStart; /按下鼠标左键那一刻的时间BOOL m_bDragging; /标识是否正在拖动过程中CImageList* m_pDragImage; /拖动时显示的图象列表HTREEITEM m_hItemDragS; /被拖动的标签HTREEITEM m_hItemDragD; /接受拖动的标签/AFX_MSG(CXTreeCtrl)afx_msg void OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult);afx_msg void OnMouseMove(UINT nFlags, CPoint point);afx_msg void OnLButtonUp(UINT nFlags
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1