A Multi-Level CCheckListbox

Recently, I was in the need of a control that allowed the users the ability to check multiple items in a CListbox type of fashion. I would of used the common MFC control CCheckListBox but I needed the items to be presented in a hierarchy and be totally customizable (font, colors, images, etc.) for each individual item. I also thought about using the MFC CTreeCtrl and do my own custom drawing but I really wanted the CListbox look and feel along without the ability to expand and collapse each item. So...here's my solution...

The interface's supplied to use this class is as follows (examples to use them are below

Each item added to the control is represented by the following structure..

 LISTITEM* pParentItem; // Points to its parent
 int nCheckedState; // It check state

 // Total width of this item (includes bitmap & indents)
 int nTotalWidth;

 int nTextLength; // Length of the text in bytes
 int nLevel;   // How many tabs it is over
 // Is this item selected (multiple selection eventually)
 bool bSelected;

 DWORD dwID;   // Id accociated with the item
 CString csText;   // Text of the item

 // Appearence
 COLORREF crTextColor; // Text color
 COLORREF crTextHighColor; // Text selection color
 COLORREF crBgHighlightColor; // Background highlight color
 // List to other child list items
 CPtrList m_ItemList;  // List of all this items children
You can obtain this structure for every item in the control to get and set its attributes. Be careful not to change certian items though, such as nLevel and nTextLength. (these are for internal use only!)

User Functions

BOOL Create( CRect Rect, CWnd* pParent, UINT uID,
 UINT nCheckBitmap, 
 UINT nUnCheckBitmap, 
 UINT nMiddleCheckBitmap,
 COLORREF crBkColor = 
  GetSysColor(COLOR_WINDOW), CFont* pCustomFont = NULL);

LISTITEM* AddString(  CString csText,
LISTITEM* pParentItem = NULL,
 int nCheckState = UNCHECKED,
 DWORD dwID = -1,  
 COLORREF crTextColor = GetSysColor(COLOR_INFOTEXT),
 COLORREF crBgHighlightColor = GetSysColor(COLOR_HIGHLIGHT));

int  DeleteString(int nItem);  
int  GetCount(LISTITEM* pParentItem = NULL);
int  GetTopIndex();
int  SetTopIndex(int nTop);
DWORD GetItemData(int nItem);
int  SetItemData(int nItem, DWORD dwID);
LISTITEM* GetItem(int nItem);
int  GetText(int nItem, CString* pString );  
int  GetTextLen(int nItem );  
int  GetCurSel();
int  SetCurSel(int nItem);
int  SetCheck(int nItem, int nCheckState );
int  GetCheck(int nItem);
void  ResetContent();
Most of the above functions work identical to the standard CListBox functions so I will spare you the verbiage in how to use them. I will however, elaborate on some specific ones that are new to this class or work a little differently then the norm.

BOOL Create( CRect Rect, CWnd* pParent, UINT uID, ...)
In the create call you must specify the three bitmaps you want to be used to display the states of each item. These imaged must be the same exact size! You can also see that the background color can be set along with the font to use.

LISTITEM* AddString( CString csText, ...)
In the AddString call, you can set the items parent (by using the item that is returned in a previous AddString call) You can also set a lot of custom features such as: State, ID, and lots of colors!

int DeleteString(int nItem);
Removes the item sent, PLUS all of the items children, and their children, etc.

int GetCount(LISTITEM* pParentItem = NULL);
Returns the total items in the control if NULL is sent in or the number of children for a specific item.

LISTITEM* GetItem(int nItem);
Both of these functions find an item based on either their positions in the control or the ID set for the them. As you can see, it returns the entire structure that represents the item.

There are other inline functions that are also available. These are (hopefully) self-explanatory.

inline int   GetWidestItem()  { return m_nWidestItem; };
inline int   GetLineHeight()  { return m_nLineHeight; };
inline CPen*  GetBkPen()   { return m_pBkPen; };
inline CBrush*  GetBkBrush()  { return m_pBkBrush; };
inline CFont*  GetTextFont()  { return m_pTextFont; };
inline int   GetImageWidth()  { return m_cBitmapDimen.cx; };
inline int   GetImageHeight() { return m_cBitmapDimen.cy; };
inline CBitmap*  GetCheckImage()  { return m_pCheck; };
inline CBitmap*  GetUnCheckImage() { return m_pUnCheck; };
inline CBitmap*  GetMiddleImage() { return m_pMiddleCheck; };
Here's some sample code in how to fill and manipulate items in the control...

// Create the Control
LISTITEM* pParentItem = NULL;
m_pCheckList = new CCheckList();
if( !m_pCheckList->Create( CRect(50,50,300,300), this, 10001,

// Add some items

// Root Item
pParentItem = m_pCheckListStandard->AddString("Exotics"); 

// Sub Item
m_ pCheckList ->AddString("Lamborghini", pParentItem );  

// Sub Item
m_ pCheckList ->AddString("Corvette", pParentItem );  

// Sub Item
m_ pCheckList ->AddString("Vector", pParentItem );   

// Sub Item
m_ pCheckList ->AddString("Hummer", pParentItem );  

//  Sub-Sub Item
pParentItem = m_ pCheckList ->AddString("Porsche", pParentItem ); 

//  Sub-Sub Item
m_ pCheckList ->AddString("Boxster", pParentItem );  

//  Sub-Sub Item
m_ pCheckList ->AddString("928 S4", pParentItem);   

//  Sub-Sub Item
m_ pCheckList ->AddString("959", pParentItem );   
// Root Item
m_ pCheckList ->AddString("Luxury");     

// Root Item
m_ pCheckList ->AddString("Trucks");    

// Root Item
m_ pCheckList ->AddString("Sport Utility Vehicles");  

// Root Item
m_ pCheckList ->AddString("Classics");    

// Function uses
// Get Total Count
CString csMessage;
csMessage.Format("There are a total of %d items", 
 m_pCheckListStandard->GetCount() );


// Get and Set the top index
csMessage.Format("The top index is: %d", 
 m_pCheckListStandard->GetTopIndex() );


// Different ways to get an item
LISTITEM* pItem = 

pItem = m_pCheckList->GetItem((DWORD)5000);

// Get and Set the Item data

csMessage.Format("The Data for this item is: %ld", dwID );
m_pCheckListStandard->SetItemData(6, 2000);

// Get the text and text length
CString csText;
m_pCheckListStandard->GetText( 6, &csText );
int nTemp = m_pCheckListStandard->GetTextLen( 7 );

// Get and set the current selection
nTemp = m_pCheckListStandard->GetCurSel();

// Get and Set Checks
m_pCheckListStandard->SetCheck(6, CHECKED);
nTemp = m_pCheckListStandard->GetCheck(6);

// Remove one item and all its subitems (if it has them)

// Delete eveything

I have included the standard looking three states for checkboxes..but feel free to think outside the box and create your own!


Download source - 18 Kb


  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Managing your company's financials is the backbone of your business and is vital to the long-term health and viability of your company. To continue applying the necessary financial rigor to support rapid growth, the accounting department needs the right tools to most efficiently do their job. Read this white paper to understand the 10 essentials of a complete financial management system and how the right solution can help you keep up with the rapidly changing business world.

  • Protecting business operations means shifting the priorities around availability from disaster recovery to business continuity. Enterprises are shifting their focus from recovery from a disaster to preventing the disaster in the first place. With this change in mindset, disaster recovery is no longer the first line of defense; the organizations with a smarter business continuity practice are less impacted when disasters strike. This SmartSelect will provide insight to help guide your enterprise toward better …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds