.: Home :: Contact Us :.  
  



Hans Dietrich Software

free and licensed software

   

XListCtrl

The use of list controls is becoming very common now, and is used by many apps with the need for some sort of list display. I have used list controls in many projects, and naturally have developed my own classes to display different colors, fonts, and progress bars in list control.

Recently I needed a list control with a checkbox like Hotmail. With a list like Hotmail you have checkbox in column header, and checkboxes in each subitem in that column. To set a check in every subitem, you check the checkbox in the column header. Similarly, if you uncheck one of the subitems, then the checkbox in the column header also gets unchecked.

What's New in 1.6.1

New Features

  • Buttons - thanks to Gregory S Wright for sharing his button implementation
screenshot
  
  • Can now set alignment of subitems independent of header
screenshot
  
  • Set empty list message and text color; suggested by Allen Rossouw
screenshot
  
  • Now builds under VS6, VS2005, and VS2008; demo workspace included for each
screenshot
  
  • Header now drawn with XP theming; requested by bambou51 and others. The header is now drawn using NM_CUSTOMDRAW messages, just like the list control.
screenshot
  
  • All checkboxes now drawn with XP theming using DrawThemeBackground() function from uxtheme.dll
screenshot
  
  • Can specify color for header text using SetHeaderItemTextColor() (passing -1 for column will set text color for all columns); requested by zacobi
screenshot

Please see the Revision History for more changes.

XListCtrl Features

The new CXListCtrl list control class supports these features:

  • Text and background colors may be specified for each subitem.
  • One or more subitem text may be displayed as normal or bold font.
  • One or more subitems may be switched from displaying text to displaying a progress bar, and then back again to text.
  • Custom text may be specified for progress bar, instead of just displaying usual 10%, 20%, etc. Also, there is option to display no text for progress bar, just the bar itself.
  • One or more subitems may contain checkbox, with or without text.
  • One or more subitems may contain combobox control.
  • One or more subitems may contain edit control.
  • One or more subitems may contain button.
  • A row may be disabled, so that checkboxes are unclickable.
  • All user input can be disabled.
  • The header is displayed flat like Outlook.
  • Alignment of subitems is independent of header.

XListCtrl Demo

The demo project provides a sample app that shows what the various features look like. Press the Start button and the list control is filled with data.

screenshot

  1. Columns 1, 2, 3, 5, and 6 show header items with custom color (blue)
  2. The second column shows subitem with different background color
  3. The second column shows subitem with bold text
  4. The third column contains progress bar in row 2
  5. The fourth column shows header item with custom color (red)
  6. The fifth column shows subitem with different background color
  7. The sixth column contains buttons and text
  8. First column is specified with checkboxes
  9. The second column shows combobox
  10. The sixth row is disabled
  11. The fourth column also contains checkboxes
  12. The fifth column shows edit control
  13. The sixth column shows subitem with different text and background colors

How To Use

To integrate XListCtrl into your own app, you first need to decide if you want to include XListCtrl code into your own exe (using XListCtrl static link library), or if you want to link to XListCtrl DLL. Using DLL version of XListCtrl makes sense if you plan to use XListCtrl in several apps. The XListCtrl DLL is an MFC extension DLL, so your app must also be MFC-based.

If you plan to use and distribute DLL version of XListCtrl, do not put DLL in Windows directory. This could cause conflicts with other apps that use XListCtrl, and some future version of XListCtrl may not be compatible with the one that you distribute.

To use static XListCtrl library, define symbol XLISTCTRLLIB_STATIC before including header file XListCtrl.h. Otherwise, DLL version of XListCtrl will be linked to your app. Regardless of which version you link with, you must change your app's build environment as follows:

  1. Go to Project | Settings | C/C++ | Preprocessor and add the XListCtrl source directory to Additional include directories. Also, on the left side of the Settings dialog, choose All Configurations. Click OK to save this setting.

    screenshot

  2. Go to Project | Settings | Link | Input and add the XListCtrl library directory to Additional library path. Again, on the left side of the Settings dialog, choose All Configurations. Click OK to save this setting.

    screenshot

Automatic Library Selection

Using symbols _AFXDLL, XLISTCTRLLIB_STATIC, _DEBUG, and _UNICODE, the following code in XListCtrlLibDefs.h automatically determines which XListCtrl library to link to your app:

///////////////////////////////////////////////////////////////////////////////
// The first two letters of the library name specify the MFC/XListCtrl
// build configuration as follows:
//       MFC     MFC      XListCtrl    XListCtrl
//       DLL    Static       DLL        Static
// DD     x                   x                
// DS     x                               x    
// SS             x                       x    
// SD    -----------  not provided  -----------  
//
// The third letter specifies Release/Debug.
// The fourth letter specifies ANSI/UNICODE.
///////////////////////////////////////////////////////////////////////////////

#ifndef XLISTCTRLLIB_NOAUTOLIB
    #if defined _AFXDLL && !defined XLISTCTRLLIB_STATIC
        // MFC shared DLL with XListCtrl shared DLL
        #ifdef _UNICODE    
            #ifdef _DEBUG
                #pragma comment(lib,"XListCtrlDDDU.lib")
                #pragma message("Automatically linking with XListCtrlDDDU.lib")
            #else
                #pragma comment(lib,"XListCtrlDDRU.lib")
                #pragma message("Automatically linking with XListCtrlDDRU.lib")
            #endif
        #else
            #ifdef _DEBUG
                #pragma comment(lib,"XListCtrlDDDA.lib")
                #pragma message("Automatically linking with XListCtrlDDDA.lib")
            #else
                #pragma comment(lib,"XListCtrlDDRA.lib")
                #pragma message("Automatically linking with XListCtrlDDRA.lib")
            #endif
        #endif
    #elif defined _AFXDLL && defined XLISTCTRLLIB_STATIC
        // MFC shared DLL with XListCtrl static lib
        #ifdef _UNICODE
            #ifdef _DEBUG
                #pragma comment(lib,"XListCtrlDSDU.lib")
                #pragma message("Automatically linking with XListCtrlDSDU.lib")
            #else
                #pragma comment(lib,"XListCtrlDSRU.lib")
                #pragma message("Automatically linking with XListCtrlDSRU.lib")
            #endif
        #else
            #ifdef _DEBUG
                #pragma comment(lib,"XListCtrlDSDA.lib")
                #pragma message("Automatically linking with XListCtrlDSDA.lib")
            #else
                #pragma comment(lib,"XListCtrlDSRA.lib")
                #pragma message("Automatically linking with XListCtrlDSRA.lib")
            #endif
        #endif
    #elif !defined _AFXDLL && defined XLISTCTRLLIB_STATIC
        // MFC static lib with XListCtrl static lib
        #ifdef _UNICODE
            #ifdef _DEBUG
                #pragma comment(lib,"XListCtrlSSDU.lib")
                #pragma message("Automatically linking with XListCtrlSSDU.lib")
            #else
                #pragma comment(lib,"XListCtrlSSRU.lib")
                #pragma message("Automatically linking with XListCtrlSSRU.lib")
            #endif
        #else
            #ifdef _DEBUG
                #pragma comment(lib,"XListCtrlSSDA.lib")
                #pragma message("Automatically linking with XListCtrlSSDA.lib")
            #else
                #pragma comment(lib,"XListCtrlSSRA.lib")
                #pragma message("Automatically linking with XListCtrlSSRA.lib")
            #endif
        #endif
    #else
        #pragma message(" ")
        #pragma message("--------------------------------------------------------------------------")
        #pragma message(" The SD build configuration (MFC static, XListCtrl DLL) is not available. ")
        #pragma message("--------------------------------------------------------------------------")
        #pragma message(" ")
        #error This build configuration is not available.
    #endif
#endif

XListCtrl Library Naming Conventions

XListCtrl Library Naming Conventions
Library Name MFC XListCtrl Build Charset
DLL Static DLL Static Debug Release ANSI UNICODE
XListCtrlDDDA image   image   image   image  
XListCtrlDDDU image   image   image     image
XListCtrlDDRA image   image     image image  
XListCtrlDDRU image   image     image   image
XListCtrlDSDA image     image image   image  
XListCtrlDSDU image     image image     image
XListCtrlDSRA image     image   image image  
XListCtrlDSRU image     image   image   image
XListCtrlSSDA   image   image image   image  
XListCtrlSSDU   image   image image     image
XListCtrlSSRA   image   image   image image  
XListCtrlSSRU   image   image   image   image
XListCtrlSDxx ——— not built ———

Building XListCtrl Libraries

To build the XListCtrl libraries, go to Build | Batch Build and select the libraries you wish to build:

screenshot

Then click on Rebuild All and the libraries will be built. By default, the .lib and .dll files are copied to the bin directory.

Tips and Tricks

  1. TRACE output - TRACE output within XListCtrl is controlled via compiler directives in the file XListCtrlLib\StdAfx.h. To disable the TRACE output, comment out the following line:
    #define ENABLE_XLISTCTRL_TRACE
  2. Checking the target - In a non-trivial application, it is easy to lose track of exactly what compiler options were used. Is it a Release build or Debug? Is it compiled for Unicode or Ansi? Dependency Walker is a free tool that will quickly answer these questions and others you may have about the product you are building. When used to examine DialogDSRU.exe, this is what Depends shows:
    screenshot    The MFC80U shows that the app was compiled for Unicode (hence the U) and is a Release build (there is no D in the name).

    Here is what Depends shows for DialogDSDA.exe:

    screenshot    The MFC80D shows that the app was compiled for Ansi (there is no U) and is a Debug build (hence the D).

  3. Compiling - To compile XListCtrl, you will need the Platform SDK. Otherwise, you will get error for header files uxtheme.h and tmschema.h.
  4. Unicode vs. Ansi - The demo dialog application projects may be compiled for either Unicode or Ansi. In VS6, this is done by defining the preprocessor symbol _UNICODE. In VS2005, this is done using a selection on the Properties | C/C++ | General tab:

    screenshot

    The XListCtrl projects have the same setting.

    Note that – for the dialog demos – you can choose between the Unicode and Ansi builds by using the combobox on the VS2005 toolbar:

    screenshot

  5. Rebuilding dialog demos - If you rebuild any of the dialog demos, be sure to use Rebuild All command. Reason: the dialog demos all share the same output file directories, and you will get linker errors if you compile only one module, and try to link with modules that were compiled with different set of build options.
  6. Eliminate flickering - When updating or filling the list control, there is sometimes flickering of list control and/or other controls on dialog. To eliminate this flickering, you may try one of the following methods:
    1. Use CListCtrl::LockWindowUpdate()/CListCtrl::UnlockWindowUpdate() to bracket the updating code.
    2. Use CListCtrl::SetRedraw(FALSE)/CListCtrl::SetRedraw(TRUE) to bracket the updating code.
    After using one of these methods, you probably should call list.UpdateWindow() to make sure control is updated. If one method doesn't completely eliminate flickering in your application, try other method to determine which works best.
  7. Using tooltips - You must first call CListCtrl::EnableToolTips(TRUE).
  8. Using combobox and edit controls - You must set LVS_EX_FULLROWSELECT style.
  9. Using buttons - Buttons require that the row height be slightly larger than normal. To increase the row height, a 1-pixel wide image list is created of the desired height. You can override this automatic behavior by calling SetItemHeight() yourself.

    Buttons can be used in any subitem, with or without adjacent text. When there is no adjacent text, the button will be centered. By convention, if there is adjacent text (set with SetItemText()), the button will be right-aligned. The text itself defaults to the same alignment as the header; this can be overriden by using SetSubItemAlignment().

    Normally buttons are sized automatically.     Automatic width
    screenshot
    You can control the width of a button by using SetButton() (the fourth parameter is the button width), or by using SetButtonWidth().       Fixed width
    screenshot
  10. Using edit boxes - If you use any edit boxes, you must implement a handler for LVN_ENDLABELEDIT. Otherwise, the default handler will return 0, meaning that the new text will be rejected. The simplest handler would be:
    void CMyDlg::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult) 
    {
        *pResult = 1;        // return 1 to accept new text, 0 to reject
    }
    The notification messages LVN_BEGINLABELEDIT and LVN_ENDLABELEDIT will always be sent by XListCtrl to its parent; you do not need to set the LVS_EDITLABELS style to receive these messages.

    Anytime after receiving LVN_BEGINLABELEDIT message, the parent can send LVM_GETEDITCONTROL to retrieve the HWND of the edit control. This can then be used to set additional edit styles, etc. In the demo dialog app, the edit style ES_UPPERCASE is set in the LVN_BEGINLABELEDIT handler. Using one of my favorite programming tools, HPS HwndSpy, I verified that the correct HWND was being returned, and also that the edit style was being set:

    screenshot

    LVN_ENDLABELEDIT will always be sent to the parent when the edit box closes. If the user pressed the Esc key, or if the parent sent the LVM_CANCELEDITLABEL message, the pszText parameter will be NULL; otherwise, the pszText parameter will not be NULL (however, the string itself may be empty, if the user erased the entry).

    The WM_XLISTCTRL_EDIT_END message is also sent to the parent when the edit box closes, but only if the edit was not cancelled (by the user pressing the Esc key, or by the parent sending the LVM_CANCELEDITLABEL message).

    In the demo dialog app, LVM_CANCELEDITLABEL is sent to XListCtrl whenever the subitem at (0,4) is edited. You can see the effect this has by looking at the log output:

    screenshot

    If you are planning on using LVM_CANCELEDITLABEL in a VS6 project, you may have to include this line at the beginning of stdafx.h:
    #define _WIN32_WINNT 0x501
  11. Customizing the header - There are several ways that the header can be customized. Here are the APIs that you can use:

    • EnableHeaderDividerLines() - show/hide divider lines between header items
    • SetHeaderAlignment() - set the text alignment (left, center, right) for all header items. Normally, this is set to DT_DEFAULT, which means that the standard column alignment is used.
    • SetHeaderSpacing() - Sets the column spacing. This is the spacing that precedes the text in a column header.
    • SetHeaderItemTextColor(column, color) - Sets the text color for the specified column
    • SetHeaderItemTextColor(-1, color) - Sets the text color for all columns. This will be overridden if SetHeaderItemTextColor() is subsequently used for a column.

Revision History

Version 1.6.3 Changes

  • Added support for multi-line tooltips (they can now also be greater than 80 characters in length).
  • Fixed crash when using scroll wheel to scroll up past top in a closed combobox.
  • Fixed problem with horizontal scrolling.

Version 1.6.2 Changes

  • Fixed problem with fast-clicking on combobox.
  • Fixed problem with vertical scrolling and gridlines.
  • Added VS2008 solution; now builds under VS6, VS2005, and VS2008; demo workspace included for each.

Version 1.6.1 Changes

  • Fixed several problems with horizontal scrolling and gridlines.

Version 1.6 Changes

  • Buttons - thanks to Gregory S Wright for sharing his button implementation.
  • Can now set alignment of subitems independent of header.
  • Set empty list message and text color; suggested by Allen Rossouw.
  • Now builds under both VS6 and VS2005.
  • Header now drawn with XP theming; requested by bambou51 and others.
  • All checkboxes now drawn with XP theming using DrawThemeBackground() function from uxtheme.dll.
  • Can specify color for all header text using SetHeaderTextColor(), and also for each individual column using SetHeaderItemTextColor(); requested by zacobi.
  • Fixed problem with subitem editing when scrolling with mouse wheel, reported by Whilibarj and Eric Jacobsen.
  • Removed GetCheckbox() and renamed GetItemCheckedState() to GetCheckedState().
  • Renamed SetItemCheckedState() to SetCheckedState(); renamed constants XHEADERCTRL_NO_IMAGE, etc., to XLISTCTRL_NO_CHECKBOX, etc.
  • Clicking on a checkbox in the header will now generate the same WM_XLISTCTRL_CHECKBOX_CLICKED message that is sent when clicking on a list control checkbox, except that the wParam parameter will be -1. The lParam parameter is the column number (zero based).
  • New functions SetAllowUserInput() and GetAllowUserInput() allow you to disable all user input (from buttons, checkboxes, combo, and edit boxes). This is a global setting and applies to all input. There is no visual indication that user input has been disabled. There are corresponding functions for the header control. This was suggested by Tom Watson.
  • New functions SaveColumns() and LoadColumns() save and restore column widths.
  • Implemented notification messages LVN_BEGINLABELEDIT and LVN_ENDLABELEDIT.
  • Implemented LVM_CANCELEDITLABEL message.
  • Implemented LVM_GETEDITCONTROL message.
  • Optimized clicking on a column with checkboxes, eliminating flicker from all columns except the one being updated.
  • Modified SetItemColors() to accept -1 for subitem number, meaning apply colors to all columns; suggested by simon heffer.
  • Added check if combobox exists before attempting to destroy it.
  • Fixed orphan combobox when clicking fast.
  • Fixed compile problem in AdvComboBox.cpp.
  • Fixed compile problem with CreateEx() function.
  • Fixed problem with gridlines disappearing in first column.
  • Fixed compile errors cause by namespace std in AdvComboBox.
  • Fixed problem with combobox leaking.
  • Fixed sequence problem where message was being sent to parent before header was updated, reported by larryp.
  • Added function GetCheckboxCount(int nSubItem) to retrieve the number of checkboxes in a column (which may be different from number of items).
  • Fixed problem where number of items rather than number of checkboxes was being used to determine if header checkbox should be checked, reported by larryp.
  • Fixed problem where edit box was not being deleted before a new one is created.
  • Fixed problem when using on multiple monitors
  • Modified lParam for the four registered messages that may be returned by XListCtrl:
    • WM_XLISTCTRL_COMBO_SELECTION
    • WM_XLISTCTRL_CHECKBOX_CLICKED
    • WM_XLISTCTRL_EDIT_END
    • WM_XLISTCTRL_BUTTON_CLICKED
    These four messages now contain item number in wParam parameter, and lParam parameter contains subitem number in low order word, and list control ID in high order word.

    Example:

    LRESULT CXListCtrlTestDlg::OnCheckbox(WPARAM wParam, LPARAM lParam)
    {
        int nItem    = (int) wParam;
        int nSubItem = (int) LOWORD(lParam);
        UINT nID     = HIWORD(lParam);
    
        TRACE(_T("nID=%d\n"), nID);
        VERIFY(nID == IDC_LIST);
    This change fixes a problem when there are multiple XListCtrl objects are on dialog. Previously, there was no simple way to determine which object sent message. Reported by simon heffer.
    INCOMPATIBILITY ALERT

    The above change to the lParam parameter may break existing code.

Version 1.5 Changes

Unreleased beta.

Version 1.4 Changes

  • Subitem editing - thanks to Oleg Matcovsky for providing code that I based this implementation on.
  • New combo box implementation.
  • Skip disabled items - fixed this bug, that allowed disabled item to be selected.
  • Set header alignment, text color, and divider lines.
  • Set cell padding.
  • Reduced flickering.
  • Header checkboxes do not require resource bitmap - the file checkboxes.bmp, is still included in download, but it is no longer really necessary.
  • Enable ellipsis for text display.
  • Get modified flag for subitems.
  • More demo build configurations - 1.4 includes both DLL and static link build configurations, with 3 types of demo apps — dialogs, MDI, and property sheet — and 12 versions of the XListCtrl libraries, including both Unicode and ANSI.
  • DLL and static library versions - beginning with this version, all XListCtrl code has been organized as libraries that you link with. Table below shows library versions available.
  • Many bug fixes!

Version 1.3 Changes

This version includes many bug fixes that have been accumulating. My thanks for all who have reported bugs. Please try this new version and let me know if you find any bugs, or have suggestions for future enhancements.

  • Added hot-tracking to combo's listbox.
  • Added compile-time option to remove support for comboboxes. (This reduce exe size by about 8 Kb). To remove combobox support, put this line in stdafx.h:
    #define DO_NOT_INCLUDE_XCOMBOLIST

    If you insert this define, you do not need to include XComboList.cpp or XComboList.h in your project.

  • Changed CXComboList::SetActive to accept scroll bar width as input parameter.
  • Fixed bug that caused string to not be displayed when clicking outside item string (reported by James Moore). This also caused problems in property pages and other places.
  • Fixed bug that caused some strings not to be selected, when drag-selecting several items quickly (reported by James Moore).
  • Fixed several problems with displaying images in header and list control (reported by Scot Brennecke).
  • Changed message map macros for NM_CLICK and LVN_COLUMNCLICK to use ON_NOTIFY_REFLECT_EX(), to allow parent to handle message also (suggested by bkupcins).
  • Fixed problem in XHeaderCtrl caused when XP theming is enabled. The GetHeaderCheckedState()/SetHeaderCheckedState() functions now use 0 = no check box, 1 = unchecked check box, 2 = checked check box. Note: The checkboxes.bmp file has also been updated, and must be replaced in all project that use 1.3 XListCtrl. The new defines XHEADERCTRL_NO_IMAGE, XHEADERCTRL_UNCHECKED_IMAGE, and XHEADERCTRL_CHECKED_IMAGE should be used when setting the image in the header control (see XListCtrlTestDlg.cpp for example).
  • Replaced calls to GetSysColor() with class variables that are set in ctor. Class variables are reloaded in response to WM_SYSCOLORCHANGE message (suggested by KarstenK).
  • Added ASSERT if combo boxes are used without LVS_EX_FULLROWSELECT style.
  • Added two registered messages that XListCtrl will send to its parent when combo box selection is changed (WM_XLISTCTRL_COMBO_SELECTION) and when check box is clicked (WM_XLISTCTRL_CHECKBOX_CLICKED). The sample app shows how to handle these new messages.
  • Added support for tooltips. To enable tooltips, you must call CListCtrl::EnableToolTips(TRUE). If you #define constant NO_XLISTCTRL_TOOL_TIPS, the tooltip support will not be included. New API's for tooltips:
    BOOL SetItemToolTipText(int nItem, int nSubItem, LPCTSTR lpszToolTipText);
    CString GetItemToolTipText(int nItem, int nSubItem);
    void DeleteAllToolTips();

Version 1.2.1 Changes

  • Added build configurations for Unicode.
  • Minor code modifications to support Unicode strings.

Version 1.2 Changes

  • Comboboxes!!! Now you can specify drop-list combobox for one or more subitem.
  • Combobox will be drawn when item is highlighted. Demo now has item hot-tracking.
  • Incorporated David Patrick's suggestion on how to subclass header control if CXListCtrl is created dynamically via Create() instead of via dialog template. See XListCtrlTestDlg.cpp for details on how to convert the demo project to create CXListCtrl dynamically.
  • Tweaked drawing of subitems to make cleaner visually.
  • Added API's for GetCurSel and SetCurSel to make coding easier.

Buy latest version

Buy XListCtrl 1.6.6 license – $40.00 per developer   
  

Free download