Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ComboTree

0.00/5 (No votes)
11 May 2003 1  
ComboBox with a tree control drop down

Sample Image

ComboTree is a hybrid ComboBox with a tree control replacing the drop down ListBox. Implementing a hierarchy of choices using multiple dependant combo or list boxes can take up a lot of screen space and can be awkward to use. A dropdown tree control can be a good replacement. As an option, the ComboTree supports a tree with three-state checkboxes for convenient multiple selection from a hierarchy of choices.

It has been tested and works on Win2000, Win98 and NT 4.0. Due to differences between these systems the technique of positioning a substitute control in place of the ListBox of an existing ComboBox upon receiving a CBN_DROPDOWN message couldn't be relied on. Instead of subclassing and modifying the behavior, this control totally replaces the existing ComboBox.

The previous version of ComboTree used a tree control with the WS_POPUP style that was a child of the ComboTree's parent window. The WS_POPUP style however caused the parent dialog to become inactive when the tree was dropped down. This version of ComboTree creates the tree control as a child of the Desktop window like the ComboBox does with its ListBox. The ComboTree subclasses the ComboTree's parent window to intercept messages when the tree is dropped down and it also forwards keyboard messages to the tree. The built in tree control's tooltips did not work in this configuration, so the ComboTree  includes a custom tooltip control to provide them.

Here are the steps needed to use a ComboTree in your project:

  1. Just as you normally would, place a ComboBox on the dialog. Set the dropdown height. The hybrid control will use the same sizes and positions as the original.
  2. Add all files named ComboTree*.cpp & .h and Subclass.cpp, Subclass.h, PupText.cpp, PupText.h to your project.
  3. If you will be using the checked tree style, import the bitmap file ComboTreeCheckboxes.bmp and give it a resource Id of "COMBOTREECHECKS" (Note: The quotes are important! The quoted resource form is used to allow the bitmap to be optional.) Alternatively, you may open the resource file for the sample project, ComboTreeShow.rc and drag and drop the "COMBOTREECHECKS" bitmap into your project's resource tab.
  4. In the header file for the dialog, add an include for ComboTree.h at the top. Manually add a ComboTree member variable, referred to as m_ComboTree below
  5. Create the ComboTree in the dialog's OnInitDialog() function. If you are using checkboxes you must call SetHasCheckboxes(TRUE) before creating the control. Create the ComboTree by subclassing the ComboBox from step one. Example syntax for creating a checked tree:
    m_ComboTree.SetHasCheckboxes(TRUE);
    m_ComboTree.SubclassDlgItem (IDC_COMBO_TREE);

    (To create a tree without checkboxes, omit the SetHasCheckboxes() call.)
  6. Populate the control using the AddString() function.
  7. Just as you normally would, use Class Wizard or edit manually to add handlers for the ComboBox notifications you want. ComboTree uses the same CBN_* notifications as a normal ComboBox.

Usage Notes:

Important note: Don't use ClassWizard and the DDX/DDV mechanism to add and associate member variables with the ComboBox. Once the original ComboBox control is subclassed it won't exist anymore.

Not all ComboBox notifications are supported, but the following ones are:
ON_CBN_SELENDOK(IDC_COMBO_TREE, OnSelendokComboTree)
ON_CBN_SELENDCANCEL(IDC_COMBO_TREE, OnSelendcancelComboTree)
ON_CBN_KILLFOCUS(IDC_COMBO_TREE, OnKillfocusComboTree)
ON_CBN_SELCHANGE(IDC_COMBO_TREE, OnSelchangeComboTree)
ON_CBN_DBLCLK(IDC_COMBO_TREE, OnDblclkComboTree)
ON_CBN_SETFOCUS(IDC_COMBO_TREE, OnSetfocusComboTree)
ON_CBN_CLOSEUP(IDC_COMBO_TREE, OnCloseupComboTree)
ON_CBN_DROPDOWN(IDC_COMBO_TREE, OnDropdownComboTree)
When accessing the control, call the ComboTree functions directly instead of sending messges. The following access functions which emulate their CComboBox equivalents are supported.
void SetWindowText (LPCTSTR Text);
CString GetWindowText ();
int GetLBText (HTREEITEM hItem, CString& rText);

HTREEITEM AddString ( LPCTSTR lpszString);
HTREEITEM FindString ( LPCTSTR lpszString, HTREEITEM hParent = NULL);
HTREEITEM SelectString( LPCTSTR lpszString, HTREEITEM hParent = NULL);

HTREEITEM GetCurSel ();
int   SetItemData (HTREEITEM hItem, DWORD dwItemData);
DWORD GetItemData (HTREEITEM hItem);
void ShowDropDown( BOOL bShowIt = TRUE );
void ResetContent ();
int  SetDroppedWidth( UINT nWidth );
int  GetDroppedWidth( );
BOOL GetDroppedState( );
int  DeleteString( HTREEITEM hItem );
void GetDroppedControlRect (LPRECT pRect);

The access functions differ in a couple of important ways from normal CComboBox functions. Functions that accept a string use the full path of the tree heirachy. For example to select the "Chipmunk" node use the full path to it:

hNode = m_ComboTree.SelectString ("Animals/Mammals/Chipmunk");

To populate the CComboBox use the AddString () function. The function will add nodes for all levels of the path that don't already exist. The HTREEITEM returned is for the end node. Example:

HTREEITEM hNode  = m_ComboTree.AddString ("Plants/Trees/Oak");

ComboTree functions accept or return a HTREEITEM where the CComboBox equivalent uses a ListBox index. CB_ERR is still used as an error return value in functions where the CComboBox equivalent uses 0 as a success return value.

In addition to the CComboBox emulation functions are the following extensions:.

// NOTIFY_TREECOMBO_CHECK notification message for check event. 

// Message map handler example: 

ON_CONTROL (NOTIFY_TREECOMBO_CHECK, IDC_COMBO_TREE, OnComboTreeCheck)

CString GetTreePath (HTREEITEM hItem);
CString GetCurrentTreePath ();
TCHAR GetPathDelimiter ();
void SetPathDelimiter (TCHAR Delimiter);
int  SetDroppedHeight (UINT nHeight);
int  GetDroppedHeight ();
HTREEITEM FindChildItemData(DWORD SearchData, HTREEITEM hItem = NULL) ;
HTREEITEM FindChildItem (LPCTSTR Label, HTREEITEM hItem = NULL) ;
HTREEITEM GetLastItem( HTREEITEM hItem ) ;
HTREEITEM GetNextItem( HTREEITEM hItem ) ;
HTREEITEM GetPrevItem( HTREEITEM hItem ) ;
HTREEITEM GetLastSibling( HTREEITEM hItem ) ;
void CollapseBranch( HTREEITEM hItem) ;
void ExpandBranch( HTREEITEM hItem ) ;
void CollapseAllSiblings( HTREEITEM hNode );
BOOL SetHasCheckboxes (BOOL bHasCheckboxes);
BOOL GetHasCheckboxes ();
BOOL SetCheck( HTREEITEM hItem, BOOL bChecked = TRUE );
BOOL IsItemChecked(HTREEITEM hItem);
HTREEITEM GetFirstCheckedItem();
HTREEITEM GetNextCheckedItem( HTREEITEM hItem );
HTREEITEM GetPrevCheckedItem( HTREEITEM hItem );

GetTreePath () and GetCurrentTreePath() return the text of the tree item prefixed with the concatenated text of its parent nodes.

Functions that contain "Check" in the name only are valid if the tree has a checked style

Three functions allow direct access to ComboTree child controls.

ComboTreeDropList& GetTree () ;
ComboTreeEdit& GetEdit () ;
ComboTreeButton& GetDropDownButton ();

GetTree(), GetEdit () and GetDropDownButton() allow direct access to the tree, edit and button controls. (Note: Use this direct access only in ways that do not conflict with the CBN_* notifications and maintenance of control state.)

The ComboTree doesn't have support for keyboard input to select tree items from within the edit control at this time. Text lookup similar to that of a drop down style combo box could be added with some additional search functionality. The edit control is currently read only.

History

  • 8 Aug 2000 - Fixed painting bug reported by Steve Roach as well as a few other things I overlooked in emulating the droplist style ComboBox, like highlighting the control when it it gets focus, dropping down the tree when the edit gets a mouse click and disabling mouse and context menu text manipulation.
  • 9 May 2003 - New version of ComboTree fixes all the known bugs, adds three-state checkbox. Thanks to all who reported them! Credits to Magerusan Grigore Cosmin's article for fix to dialog inactivation when tree is dropped down, Paul DiLascia's article for custom tooltips and Zafir Anjum article for three-state checkboxes.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here