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