VC 樹控制元件的拖拽實現 MFC
只需要將你的樹控制元件型別改成CXTreeCtrl,並將以下標頭檔案:XTreeCtrl.h和實現檔案:XTreeCtrl.cpp包含進你的工程。
然後在void CXTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)這個函式中加入你自己的響應程式碼,即可完成樹控制元件的拖拽效果。
//XTreeCtrl.h
--------------------------------------------------------------------------------------------------------------------------
#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();
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
--------------------------------------------------------------------------------------------------------------------------
//XTreeCtrl.cpp
--------------------------------------------------------------------------------------------------------------------------
#include "stdafx.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);
}
--------------------------------------------------------------------------------------------------------------------------
有問題找我