现在的位置: 首页 > 综合 > 正文

VC 树控件的拖拽实现 MFC

2013年02月15日 ⁄ 综合 ⁄ 共 6378字 ⁄ 字号 评论关闭

只需要将你的树控件类型改成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);

}

--------------------------------------------------------------------------------------------------------------------------

 

有问题找我

 

抱歉!评论已关闭.