I wrote a base class from which the MFC users can derive their TreeView
classes in a document-view based application instead of CTreeView. This
class adds to CtreeView build-in drag-and-drop support.
All that the developer have to do is to add this class to the AppWizard
generated project (with CTreeView as a View base class) and to replace the
base of the view class from CTreeView to CTreeViewExt. After that, he/she
has to overwrite the virtual functions of the base, which interface is self
explantory.
That’s all, the drag-and-drop tree view will be up and running !
Header file
#if !defined(AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_) #define AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 // TreeViewExt.h : header file // ///////////////////////////////////////////////////////////////////////////// // CTreeViewExt view class CTreeViewExt : public CTreeView { protected: CTreeViewExt(); // protected constructor used by dynamic creation DECLARE_DYNCREATE(CTreeViewExt) // Attributes public: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CTreeViewExt) protected: virtual void OnDraw(CDC* pDC); // overridden to draw this view //}}AFX_VIRTUAL // Implementation protected: HTREEITEM m_hDraggedItem; BOOL m_bDraggingNow; CImageList *m_pDragImageList; virtual ~CTreeViewExt(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif // Generated message map functions protected: virtual void CopyItemProperties(HTREEITEM hNewItem, HTREEITEM hDraggedItem); virtual BOOL IsItemCanBeDroppedOn(HTREEITEM hSource, HTREEITEM hTarget); virtual BOOL ItemCanBeDragged(HTREEITEM hItem); //{{AFX_MSG(CTreeViewExt) 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 DECLARE_MESSAGE_MAP() }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately before the previous line. #endif // !defined(AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_)
Implementation file
// TreeViewExt.cpp : implementation file // #include "stdafx.h" #include "TreeViewExt.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CTreeViewExt IMPLEMENT_DYNCREATE(CTreeViewExt, CTreeView) CTreeViewExt::CTreeViewExt() { m_bDraggingNow = FALSE; m_hDraggedItem = NULL; m_pDragImageList = NULL; } CTreeViewExt::~CTreeViewExt() { } BEGIN_MESSAGE_MAP(CTreeViewExt, CTreeView) //{{AFX_MSG_MAP(CTreeViewExt) ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag) ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTreeViewExt drawing void CTreeViewExt::OnDraw(CDC* pDC) { CDocument* pDoc = GetDocument(); // TODO: add draw code here } ///////////////////////////////////////////////////////////////////////////// // CTreeViewExt diagnostics #ifdef _DEBUG void CTreeViewExt::AssertValid() const { CTreeView::AssertValid(); } void CTreeViewExt::Dump(CDumpContext& dc) const { CTreeView::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CTreeViewExt message handlers void CTreeViewExt::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; if (!m_bDraggingNow) { if (ItemCanBeDragged(pNMTreeView->itemNew.hItem)) { CTreeCtrl& tree = GetTreeCtrl(); tree.SetCapture(); m_bDraggingNow = TRUE; m_hDraggedItem = pNMTreeView->itemNew.hItem; tree.Select(m_hDraggedItem, TVGN_CARET); m_pDragImageList = tree.CreateDragImage(m_hDraggedItem); m_pDragImageList->DragEnter(&tree, pNMTreeView->ptDrag); m_pDragImageList->BeginDrag(0, CPoint(0, 0)); } } *pResult = 0; } void CTreeViewExt::OnMouseMove(UINT nFlags, CPoint point) { if (m_bDraggingNow) { CTreeCtrl& tree = GetTreeCtrl(); m_pDragImageList->DragEnter(&tree, point); m_pDragImageList->DragMove(point); } CTreeView::OnMouseMove(nFlags, point); } void CTreeViewExt::OnLButtonUp(UINT nFlags, CPoint point) { if (m_bDraggingNow) { ReleaseCapture(); m_bDraggingNow = FALSE; m_pDragImageList->EndDrag(); delete m_pDragImageList; m_pDragImageList = NULL; CTreeCtrl& tree = GetTreeCtrl(); UINT flags; HTREEITEM hTargetItem = tree.HitTest(point, &flags); if (hTargetItem != NULL && IsItemCanBeDroppedOn(m_hDraggedItem, hTargetItem)) { HTREEITEM hNewItem = tree.InsertItem("Untitled", hTargetItem); CopyItemProperties(hNewItem, m_hDraggedItem); if (nFlags != MK_CONTROL) tree.DeleteItem(m_hDraggedItem); } m_hDraggedItem = NULL; } CTreeView::OnLButtonUp(nFlags, point); } BOOL CTreeViewExt::ItemCanBeDragged(HTREEITEM hItem) { return FALSE; } BOOL CTreeViewExt::IsItemCanBeDroppedOn(HTREEITEM hSource, HTREEITEM hTarget) { return FALSE; } void CTreeViewExt::CopyItemProperties(HTREEITEM hNewItem, HTREEITEM hDraggedItem) { }