// XTreeCtrl.h : header file
#if !defined(AFX_XTREECTRL_H__3EF12526_EF66_4FD9_A572_59476441D79A__INCLUDED_)
#define AFX_XTREECTRL_H__3EF12526_EF66_4FD9_A572_59476441D79A__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class
CXTreeCtrl :
public
CTreeCtrl
{
// Construction
public
:
CXTreeCtrl();
// Attributes
public
:
// Operations
public
:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CXTreeCtrl)
//}}AFX_VIRTUAL
// Implementation
public
:
virtual
~CXTreeCtrl();
// Generated message map functions
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;
//接受拖动的标签
//{{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, CPoint point);
afx_msg
void
OnLButtonDown(
UINT
nFlags, CPoint point);
afx_msg
void
OnTimer(
UINT
nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private
:
HTREEITEM CopyBranch(HTREEITEM htiBranch,HTREEITEM htiNewParent,HTREEITEM htiAfter);
HTREEITEM CopyItem(HTREEITEM hItem,HTREEITEM htiNewParent,HTREEITEM htiAfter);
};
#endif
CXTreeCtrl
#include "stdafx.h"
#include "DragTree.h"
#include "XTreeCtrl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static
char
THIS_FILE[] = __FILE__;
#endif
#define DRAG_DELAY 60
CXTreeCtrl::CXTreeCtrl()
{
m_bDragging =
false
;
}
CXTreeCtrl::~CXTreeCtrl()
{}
BEGIN_MESSAGE_MAP(CXTreeCtrl, CTreeCtrl)
//{{AFX_MSG_MAP(CXTreeCtrl)
ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag)
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDOWN()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
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);
}
BOOL
CDragTreeDlg::OnInitDialog()
{
CDialog::OnInitDialog();
…………………….
//此处代码省略
// TODO: Add extra initialization here
m_image.Create ( IDB_TREEIMAGE,16,1,RGB(255,255,255) );
m_wndTree.SetImageList ( &m_image,TVSIL_NORMAL );
HTREEITEM hti1 = m_wndTree.InsertItem ( _T(
"唐詩"
),0,1 );
HTREEITEM hti2 = m_wndTree.InsertItem ( _T(
"宋詞"
),0,1 );
HTREEITEM hti3 = m_wndTree.InsertItem ( _T(
"元曲"
),0,1 );
HTREEITEM hti4 = m_wndTree.InsertItem ( _T(
"李白"
),0,1,hti1 );
m_wndTree.InsertItem ( _T(
"靜夜思(床前明月光)"
),0,1,hti4 );
m_wndTree.InsertItem ( _T(
"將進酒(君不見黃河之水天上來)"
),0,1,hti4 );
m_wndTree.InsertItem ( _T(
"望廬山瀑布(日照香爐生紫煙)"
),0,1,hti4 );
m_wndTree.InsertItem ( _T(
"蜀道難(噫吁戲,危乎高哉)"
),0,1,hti4 );
HTREEITEM hti5 = m_wndTree.InsertItem ( _T(
"杜甫"
),0,1,hti1 );
m_wndTree.InsertItem ( _T(
"蜀相(丞相祠堂何處尋)"
),0,1,hti5 );
m_wndTree.InsertItem ( _T(
"春望(國破山河在)"
),0,1,hti5 );
m_wndTree.InsertItem ( _T(
"茅屋為秋風所破歌(八月秋高風怒號)"
),0,1,hti5 );
HTREEITEM hti6 = m_wndTree.InsertItem ( _T(
"白居易"
),0,1,hti1 );
m_wndTree.InsertItem ( _T(
"長恨歌(漢皇重色思傾國)"
),0,1,hti6 );
m_wndTree.InsertItem ( _T(
"琵琶行並序(潯陽江頭夜送客)"
),0,1,hti6 );
m_wndTree.InsertItem ( _T(
"李清照"
),0,1,hti2 );
m_wndTree.InsertItem ( _T(
"柳永"
),0,1,hti2 );
return
TRUE;
// return TRUE unless you set the focus to a control
}