Category Listbox

Without checkboxes. (Default) With checkboxes.

Environment: Visual C++ 6

Description

This control mimics the behavior of Microsoft Outlook's categorized listbox. It displays a list of categories and each category has its own list of items. Categories can be opened to reveal their items or closed to hide them. The idea is to help improve list organization and to make it easier for users to find what they are looking for.

Categories have the following attributes:

  • Are indicated in the list with a grey background.
  • Category name must be unique. (They are case sensitive.)
  • Can have 0 to N items under them.
  • Have open/close buttons to show/hide their items.
  • Can be opened/closed by double-clicking them or by pressing the space bar.

Category items have the following attributes:

  • Must be assigned to a category.
  • Item name does not have to be unique.
  • Can have a checkbox displayed next to it. (Microsoft Outlook does not have this feature.)
  • Checkboxes can be checked/unchecked by clicking them or by pressing the space bar.
  • Items can store DWORD data with them. (CListBox has this feature.)

Other supported features include:

  • Sorts categories and their items if the LBS_SORT style has been set.
  • Supports selection modes Single, Multiple, Extended, and None.
  • SHOULD support unicode. (I haven't verified this.)

Implementation

The category listbox class is derived from the MFC CListBox class. Most of CListBoxs functions can still be used; however, some functions have been protected, thereby forcing you to use this class's functions instead. You cannot use the following CListBox functions with this class:

   AddString( LPCTSTR pString );
   InsertString( int iIndex, LPCTSTR pString );
   DeleteString( int iIndex );
   GetItemData( int iIndex );
   SetItemData( int iIndex, DWORD dwValue );

The category listbox class has been made as simple as possible to make it easy for you to add this control to your project. You only need to add the files "CatListBox.cpp" and "CatListBox.h" to your project. That's it! You do not have to add any images to your resource file because this class draws its buttons and checkboxes itself.

To add this control to your dialog, do the following:

  1. Add a listbox to your dialog's resource.
  2. Set up your listbox's resource for "Owner Draw: Fixed" and check "Has Strings".
  3. Create a CCatListBox member variable in your dialog's code. For example...
    #include "CatListBox.h"
    class MyDialog : public CDialog
    {
      public:
      // Dialog Data
      //{{AFX_DATA( MyDialog )
      enum { IDD = IDD_MY_DIALOG };
      CCatListBox m_lstCategories; // Create your variable here.
      //}}AFX_DATA
    }
    
    // Subclass the listbox here.
    // Make sure to replace IDC_LISTBOX_ID with the 
    // one you're using.
    void MyDialog::DoDataExchange( CDataExchange* pDX )
    {
      CDialog::DoDataExchange( pDX );
      //{{AFX_DATA_MAP( MyDialog )
      DDX_Control( pDX, 
                   IDC_LISTBOX_ID, 
                   m_lstCategories );  // Subclass it!
      //}}AFX_DATA_MAP
    }
    

Downloads

Download demo project - 20 Kb
Download source - 2 Kb


Comments

  • Killer Implementation. Great design.

    Posted by Legacy on 06/27/2003 12:00am

    Originally posted by: Digital Sunrise

    Gave me lots of ideas on what to do with an owner drawn list box, even from WIN32.

    Reply
  • Can we add drag and drop function in this nice class?

    Posted by Legacy on 06/18/2003 12:00am

    Originally posted by: Yihong Yang

    Hi, buddy:
    I just use this class in my application. Really nice job! But I'm considering if we can add drag and drop function in this class that make it more powerful. Any suggestion or new work would be highly appreciated.

    David Yang

    Reply
  • A bug (not the checkbox issue)???

    Posted by Legacy on 05/16/2003 12:00am

    Originally posted by: Nigel Johnson

    Superb stuff, but for a small issue... probably me... :)
    
    

    I am trying to use the list box to categorise files. the
    categories are the directories, and the items, the files.

    I use the file dialog to list a load of files to add, and
    they get added correctly...

    CppString dir = f.path();
    CppString fn = f.fileName();
    if(m_lstFiles.FindCategory(dir) == -1)
    {
    m_lstFiles.AddCategory(dir);
    }
    m_lstFiles.AddCategoryItem(dir, fn);

    I add 3 entries (a\m\c.txt, a\b.txt, and a\N\m.txt) This
    traces through alright. and produces corectly...

    a\m
    c.txt
    a
    b.txt
    a\N
    m.txt

    But, when I come to collect the data,

    int ccount = m_lstFiles.GetCategoryCount();
    for(int c =0; c < ccount; c++)
    {
    CppString cat = (char*)(m_lstFiles.GetCategoryName(c));
    int icount = m_lstFiles.GetCategoryItemCount(cat);

    for(int i =0; i < icount; i++)
    {
    CppString item = (char*)(m_lstFiles.GetCategoryItemName(cat, i));
    m_vFiles.push_back((char*)(cat + "\\" + item));
    }
    }

    The problem occurs on the bit
    CppString cat = (char*)(m_lstFiles.GetCategoryName(c));

    when c is 0 cat = a\m
    when c is 1 cat = a\m
    when c is 2 cat = a

    Anyone else seen this, or know why its happening... maybe a
    fix so I don't have to brush up on my STL :)

    Thanks
    Nigel

    Reply
  • GREATAAAAaaaa !!!

    Posted by Legacy on 04/22/2003 12:00am

    Originally posted by: Zvika F.

    i realy like the idea and the implementation !!

    Suggesion:

    make the structure "internal classes" (you'll have to make some modifications but it's more elegant)

    Reply
  • Very nice implementation

    Posted by Legacy on 04/17/2003 12:00am

    Originally posted by: Santanu Lahiri

    Joshua's Category List class was just what I needed. Pretty much drop in the class, include the header files, create the proper control in the dialog, and off you go. Hard to believe it was that simple. Documentation is also very good indeed. Was easy to change the behaviour just slightly to get the exact look I needed. Of course, I did not go about it the true C++ way by deriving from his class, but what the heck! Hope he forgives me!

    Reply
  • Great!

    Posted by Legacy on 03/19/2003 12:00am

    Originally posted by: Rahman

    Thanks man. I was just looking for this kind cool stuff

    Reply
  • Excellent work!

    Posted by Legacy on 11/14/2002 12:00am

    Originally posted by: Dean Jones

    Must comment on the quality job Joshua did on the category listbox! It's seldom that I've found something this well written, this well documented (comments are copious and helpful), and this helpful (saved me QUITE a bit of work on one of my projects). Note that his comments in "Checkbox issue found is not a bug" are important (I made sure that all calls to AddCategoryItem() set an item's state to either zero or one, not the default of two).

    Kudos!

    DJ

    Reply
  • Checkbox issue found is not a bug

    Posted by Legacy on 11/13/2002 12:00am

    Originally posted by: Joshua Quick

    Hello all,

    Some people are having trouble displaying checkboxes in my category listbox class. Here are some things you should know.

    Checkboxes are referred to as item states in the code. Checkboxes are shown for all items by calling the following function:
    myList.ShowCategoryItemStates( true );

    Each item's checkbox has 3 states:
    0 - Unchecked
    1 - Checked
    2 - No checkbox (The default!)
    MFC and VB's checkboxes have similar tri-state behavior.

    The item's checkbox state is set by calling the following function. (Set state to either 0, 1, or 2.)
    myList.SetCategoryItemState( category, item, state );

    The item's checkbox state can also be set when adding the item to the listbox.
    myList.AddCategoryItem( category, item, state );

    For example, to show an unchecked checkbox for the 2nd item under category "Foo", do the following...
    myList.SetCategoryItemState( "Foo", 1, 0 );
    To check it, do this...
    myList.SetCategoryItemState( "Foo", 1, 1 );

    I suppose the real bug is that the item's default checkbox state should not be 2 (no checkbox). Perhaps I should change it to 0 (unchecked)?

    I apologize for the confusion caused by this. I have commented all of my functions in the CPP file if you haven't seen them already. However, due to the responses I've received, this shows that I have not documented my work well enough.

    Thank you for your feedback!
    - Josh

    Reply
  • Neat item

    Posted by Legacy on 06/22/2002 12:00am

    Originally posted by: Garry Birch

    Sure as hell looks good Josh. Don't understand a damn thing written but nice to know that your good enough for publishing.

    Garry

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

Top White Papers and Webcasts

  • The impact of a data loss event can be significant. Real-time data is essential to remaining competitive. Many companies can no longer afford to rely on a truck arriving each day to take backup tapes offsite. For most companies, a cloud backup and recovery solution will eliminate, or significantly reduce, IT resources related to the mundane task of backup and allow your resources to be redeployed to more strategic projects. The cloud - can now be comfortable for you – with 100% recovery from anywhere all …

  • When it comes to desktops – physical or virtual – it's all about the applications. Cloud-hosted virtual desktops are growing fast because you get local data center-class security and 24x7 access with the complete personalization and flexibility of your own desktop. Organizations make five common mistakes when it comes to planning and implementing their application management strategy. This eBook tells you what they are and how to avoid them, and offers real-life case studies on customers who didn't let …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds