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..

struct LISTITEM
{
 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 crTextHighColor = GetSysColor(COLOR_HIGHLIGHTTEXT),
 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);
LISTITEM* GetItem(DWORD dwID);
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);
LISTITEM* GetItem(DWORD dwID);
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,
IDB_CHECK, IDB_UNCHECK, IDB_MIDDLECHECK )) 
{
 return;
}

// 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() );

AfxMessageBox(csMessage); 

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

AfxMessageBox(csMessage); 
m_pCheckListStandard->SetTopIndex(6);

// Different ways to get an item
LISTITEM* pItem = 
 m_pCheckListStandard->GetItem(
  m_pCheckListStandard->GetTopIndex());

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

// Get and Set the Item data
DWORD dwID = 
 m_pCheckListStandard->GetItemData(
  m_pCheckListStandard->GetTopIndex());

csMessage.Format("The Data for this item is: %ld", dwID );
AfxMessageBox(csMessage);
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
m_pCheckListStandard->SetCurSel(6);
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)
m_pCheckListStandard->DeleteString(6);

// Delete eveything
m_pCheckListStandard->ResetContent();

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

Downloads

Download source - 18 Kb


Comments

  • 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

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

  • With 81% of employees using their phones at work, companies have stopped asking: "Is corporate data leaking from personal devices?" and started asking: "How do we effectively prevent corporate data from leaking from personal devices?" The answer has not been simple. ZixOne raises the bar on BYOD security by not allowing email data to reside on the device. In addition, Zix allows employees to maintain complete control of their personal device, therefore satisfying privacy demands of valued employees and the …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds