Click here to Skip to main content
Click here to Skip to main content
Go to top

Tree Control Offering Drag and Drop, Folder Auto-expansion, New/edit/delete, and Button Move

, 29 Mar 2010
Rate this:
Please Sign up or sign in to vote.
A basic tree control that ties together all the functionality to make items fully editable and moveable.
ExDragDropCtrl

Introduction

This code ties together a number of things I really wanted my fully draggable/moveable tree control to be able to do, including adding new folders, renaming any items, and deleting any items. The particular things that this control allows are:

  • Full drag and drop functionality, including a drag image and indicator to show where the item will be dropped, i.e., to help differentiate between dropping an item in a folder or after the folder
  • Move Up/Down buttons for simple item navigation, including into and out of folders
  • New folders, renaming, and deletion, including deletion of entire folders

Background

This code is based initially on Frederic My's freeware tree control at www.fairyengine.com. Thanks Frederic.

Using the Code

The extended tree control (CTreeCtrlDrag) is contained within the source files TreeCtrlDrag.cpp and .h.

To use the control, simply replace the CTreeCtrl declaration in your dialog with CTreeCtrlDrag. As it's derived from CTreeCtrl, it can be initialised as per normal. The dialog then needs to pass any user input down to the tree control as per the following code, which would be in the dialog class...

//////////////////////////////////////////////////////////////////////
// Move tree item one place up
void CDragDropView::OnBtnUp()
{
    m_Tree.MoveItemUp();
    m_Tree.SetFocus();
}

//////////////////////////////////////////////////////////////////////
// Move tree item one place down
void CDragDropView::OnBtnDown()
{
    m_Tree.MoveItemDown();
    m_Tree.SetFocus();
}

//////////////////////////////////////////////////////////////////////
// Tree selection has changed, so check status of Up and Down buttons
void CDragDropView::OnTreeSelChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
    m_fbtnUp.EnableWindow(m_Tree.ShouldUpBtnBeEnabled());
    m_fbtnDown.EnableWindow(m_Tree.ShouldDownBtnBeEnabled());
}

void CDragDropView::OnBtnNewFolder()
{
 m_Tree.CreateNewFolder();
}

void CDragDropView::OnBtnRename()
{
 m_Tree.RenameSelected();
}

void CDragDropView::OnBtnDelete()
{
 m_Tree.DeleteSelected();
}

In the application where I use this for real, I link each tree item to a data structure, so I need to know when items are deleted or moved. When a tree item is moved, it is in fact deleted and recreated in the target location. So I need to know what the old and new tree items are. This is done automatically within the CTreeCtrlDrag control, and takes the form of user defined messages posted back to the parent window (dialog). They would be handled in the calling dialog like this...

BEGIN_MESSAGE_MAP(CDlgQuickGraphOrganise, CDialog)
 //{{AFX_MSG_MAP(CDlgQuickGraphOrganise)
    ON_MESSAGE(UWM_TREEMOVECOMPLETE, OnTreeMoveComplete)
    ON_MESSAGE(UWM_TREEITEMDELETED, OnItemDelete)
    ON_MESSAGE(UWM_TREEBEGINEDIT, OnBeginLabelEdit)
    ON_MESSAGE(UWM_TREEENDEDIT, OnItemRenamed)
    ON_MESSAGE(UWM_TREERBUTTONDOWN, OnRButtonDown)
    ON_MESSAGE(UWM_TREELBUTTONDBLCLICK, OnBtnCreategraph)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

..

//============================================================
// Tree Callback Message Handlers
//============================================================
//////////////////////////////////////////////////////////////
// A tree item has been moved successfully,
// so swap references to the old tree item with the new
// one. In other words, a tree item has been deleted
// and recreated somewhere else.
void CDlgQuickGraphOrganise::OnTreeMoveComplete(WPARAM wParam,
                                                LPARAM lParam)
{
    HTREEITEM hOld = (HTREEITEM)wParam;
    HTREEITEM hNew = (HTREEITEM)lParam;
    // Sanity check the move parameters
    ASSERT((hNew != NULL) && (hOld != NULL));
    ...
}

//////////////////////////////////////////////////////////////
// A tree item has been deleted successfully,
// so add it to the Deleted Items list
void CDlgQuickGraphOrganise::OnItemDelete(WPARAM wParam,
                                          LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    HTREEITEM hOld = (HTREEITEM)wParam;
    ...
}

//////////////////////////////////////////////////////////////
// If the user is trying to edit the root item,
// make a beep sound and cancel the edit by setting
// the pResult value to 1.
void CDlgQuickGraphSummary::OnBeginLabelEdit(NMHDR *pNMHDR,
                                             LRESULT *pResult)
{
    LPNMTVDISPINFO pTVDispInfo =
       reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
    HTREEITEM hItem = pTVDispInfo->item.hItem;
    if (hItem == m_Tree.GetRootItem())
    {
        // We don't allow the user to edit the root folder.
        *pResult = 1;
        MessageBeep((UINT)-1);
    }
}

//////////////////////////////////////////////////////////////
// We've successfully changed an item name - we may want to
// post-process the changed item.
void CDlgQuickGraphOrganise::OnItemRenamed(WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    HTREEITEM hItem = (HTREEITEM)wParam;
    ...
}

In this instance, the user defined messages (e.g., UWM_TREEBEGINEDIT) are set in StdAfx.h.

Other points to note:

  • CTreeCtrlDrag needs to be able to ascertain whether a particular tree item in a folder could be empty, so it assumes the image used for folders is always the same, i.e., using the FOLDER_IMAGE define. If you're using an image list and the index of the folder image varies from use to use, you'll have to do something a bit more clever here.

Points of Interest

While I've been coding for 4 or so years, I know I've still heaps to learn. Please, if you see any ways to improve this control or my style in general, all constructive feedback would be hugely appreciated. Note - this is only with reference to TreeCtrlDrag.cpp and .h, which are the files I've specifically worked on.

History

  • 21 Jan 2010 - Initial release
  • 26 Jan 2010 - Fixed a memory leak in TidyUpEndOfDrag() - thanks Tom
  • 26 Jan 2010 - Added a check for duplicate items when moving/renaming. When setting up the tree, call m_Tree.SetNoDuplicates(TRUE), to turn on checking for duplicate items in the current tree folder. See the additional code wherever a move occurs and after renaming (in OnEndLabelEdit()).
  • 17 Feb 2010 - Fixed a bug in return messages for movement of folder using the up and down buttons where the message was only being returned for the parent item, not any sub-items. Added a static to display the messages being received by the parent dialog. Added double click response to calling dialog to process a double click on a non-tree item. Added callback for right mouse click to allow calling dialog to context menu options.
  • 29 Mar 2010 - Fixed a bug in the control

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Phil Outram

United Kingdom United Kingdom
No Biography provided

Comments and Discussions

 
GeneralBottom item Pinmemberredgreenloko25-Aug-11 8:08 
BugBug Pinmemberredgreenloko24-Aug-11 5:46 
GeneralRe: Bug PinmemberPhil Outram24-Aug-11 22:15 
QuestionDialog Class PinmemberMember 789338710-Aug-11 7:55 
AnswerRe: Dialog Class PinmemberPhil Outram10-Aug-11 22:12 
GeneralGreat control PinmemberVincent_RICHOMME5-Aug-10 23:44 
GeneralMultiple Tree Drag n' Drop PinmemberRakeshManohar4-Mar-10 0:18 
GeneralRe: Multiple Tree Drag n' Drop PinmemberPhil Outram29-Mar-10 21:56 
GeneralMemory leak Pinmembertom-kaltofen26-Jan-10 5:14 
GeneralRe: Memory leak PinmemberPhil Outram26-Jan-10 6:49 
GeneralRe: Memory leak PinmemberVictor Nijegorodov26-Jan-10 22:50 
GeneralRe: Memory leak PinmemberPoreZ6-Mar-10 7:28 
GeneralRe: Memory leak PinmemberPhil Outram29-Mar-10 2:39 
GeneralMy vote of 2 PinmemberAlexandre GRANVAUD21-Jan-10 23:31 
GeneralRe: My vote of 2 PinmemberPhil Outram26-Jan-10 7:34 
GeneralRe: My vote of 2 PinmemberSteveKing26-Jan-10 21:54 
GeneralRe: My vote of 2 PinmemberRakeshManohar4-Mar-10 0:22 
GeneralRe: My vote of 2 PinmemberKenJohnson29-Mar-10 12:03 
GeneralRe: My vote of 2 PinmemberMukit, Ataul24-May-11 17:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 29 Mar 2010
Article Copyright 2010 by Phil Outram
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid