Click here to Skip to main content
15,881,852 members
Articles / Desktop Programming / Win32

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

Rate me:
Please Sign up or sign in to vote.
4.74/5 (27 votes)
29 Mar 2010CPOL3 min read 63.5K   2.6K   70   19
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...

C++
//////////////////////////////////////////////////////////////////////
// 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...

C++
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)


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralBottom item Pin
redgreenloko25-Aug-11 8:08
redgreenloko25-Aug-11 8:08 
BugBug Pin
redgreenloko24-Aug-11 5:46
redgreenloko24-Aug-11 5:46 
GeneralRe: Bug Pin
Phil Outram24-Aug-11 22:15
Phil Outram24-Aug-11 22:15 
QuestionDialog Class Pin
Member 789338710-Aug-11 7:55
Member 789338710-Aug-11 7:55 
AnswerRe: Dialog Class Pin
Phil Outram10-Aug-11 22:12
Phil Outram10-Aug-11 22:12 
GeneralGreat control Pin
Vince Ricci5-Aug-10 23:44
Vince Ricci5-Aug-10 23:44 
GeneralMultiple Tree Drag n' Drop Pin
RakeshManohar4-Mar-10 0:18
RakeshManohar4-Mar-10 0:18 
GeneralRe: Multiple Tree Drag n' Drop Pin
Phil Outram29-Mar-10 21:56
Phil Outram29-Mar-10 21:56 
GeneralMemory leak Pin
tom-kaltofen26-Jan-10 5:14
tom-kaltofen26-Jan-10 5:14 
GeneralRe: Memory leak Pin
Phil Outram26-Jan-10 6:49
Phil Outram26-Jan-10 6:49 
GeneralRe: Memory leak Pin
Victor Nijegorodov26-Jan-10 22:50
Victor Nijegorodov26-Jan-10 22:50 
GeneralRe: Memory leak Pin
PoreZ6-Mar-10 7:28
PoreZ6-Mar-10 7:28 
GeneralRe: Memory leak Pin
Phil Outram29-Mar-10 2:39
Phil Outram29-Mar-10 2:39 
GeneralMy vote of 2 Pin
Alexandre GRANVAUD21-Jan-10 23:31
Alexandre GRANVAUD21-Jan-10 23:31 
GeneralRe: My vote of 2 Pin
Phil Outram26-Jan-10 7:34
Phil Outram26-Jan-10 7:34 
GeneralRe: My vote of 2 Pin
SteveKing26-Jan-10 21:54
SteveKing26-Jan-10 21:54 
GeneralRe: My vote of 2 Pin
RakeshManohar4-Mar-10 0:22
RakeshManohar4-Mar-10 0:22 
GeneralRe: My vote of 2 Pin
KenJohnson29-Mar-10 12:03
KenJohnson29-Mar-10 12:03 
Ignore the dodo. You did a fine job on the article. Its better than my first.
Thanks
Ken
GeneralRe: My vote of 2 Pin
Mukit, Ataul24-May-11 17:16
Mukit, Ataul24-May-11 17:16 

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

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