Click here to Skip to main content
15,891,906 members
Articles / Desktop Programming / MFC

CListCtrl and Grouping Rows

Rate me:
Please Sign up or sign in to vote.
4.92/5 (38 votes)
27 Jul 2011CPOL3 min read 242K   8.7K   120  
Example of how to enable categories in the MFC list control
<!-- Start Article -->
<span id="ArticleContent">
<ul class="download">
<li><a href="CListCtrl_Grouping/ListCtrl_Category_Groups.zip">Download source code - 216.28 KB</a></li>
</ul>
 
<h2>Introduction</h2>
 
<p>Microsoft's <code>CListCtrl</code> has support for displaying data in a grid, but also supports grouping of data. This article will demonstrate how we can activate the grouping functionality of <code>CListCtrl</code>.</p>
 
<p>The demo application allows you to experience how grouping can be used. Just right-click a column header, to group the data according to that header.</p>
<img height="254" alt="screenshot.png" src="CListCtrl_Grouping/screenshot.png" width="471" /> 
<h2>Background</h2>
 
<p>Microsoft extended the <code>CListCtrl</code> with support for grouping, with the release of Windows XP. The new feature wasn't promoted that much, and was also limited in functionality (no collapsing of groups). The implementation was later extended with more functionality when Windows Vista was released (collapsing, footer, subtitle, and more).</p>
 
<p>There are already some .NET articles describing how to use grouping in Windows XP:</p>
 
<ul>
<li><a href="GroupListView.aspx">ListView Grouping XP Style</a></li>
 
<li><a href="GroupableListView.aspx">Groupable ListView</a></li>
</ul>
 
<p>There is also <a title="MSDN Magazine August 2007" href="http://msdn.microsoft.com/en-us/magazine/cc163384.aspx" target="_blank">MSDN - Windows Vista Control Enhancements</a>, which describes some of the new stuff in Windows Vista.</p>
 
<p>The first time I actually saw a useful application make use of this grouping feature was with <a href="http://tortoisesvn.tigris.org/tsvn_1.5_releasenotes.html#changelist-support" target="_blank">TortoiseSVN 1.5</a>.</p>
 
<h2>How To Activate Grouping in CListCtrl</h2>
 
<p>Before grouping can be activated, some things have to be in order:</p>
 
<ul>
<li>The Operating System must support Common Controls ver. 6 (Windows XP/Vista and newer)</li>
 
<li>The application must enable Common Controls ver. 6 through its manifest</li>
 
<li>The application must be compiled with <code>_WIN32_WINNT</code> set to at least <code>0x0501</code></li>
</ul>
 
<p>When the above requirements are met, we can create a group like this:</p>
 
<pre lang="C++">LRESULT CListCtrl_Category_Groups::CreateSingleGroup(int nIndex, 
                  int nGroupId, const CString&amp; strHeader)
{
    EnableGroupView( TRUE );
 
    LVGROUP lg = {0};
    lg.cbSize = sizeof(lg);
    lg.iGroupId = nGroupId;
    lg.state = LVGS_NORMAL;
    lg.mask = LVGF_GROUPID | LVGF_HEADER | LVGF_STATE | LVGF_ALIGN;
    lg.uAlign = LVGA_HEADER_LEFT;
 
    // Header-title must be unicode (Convert if necessary)
    lg.pszHeader = strHeader.GetBuffer();
    lg.cchHeader = strHeader.GetLength();
    nGroupId = InsertGroup(nIndex, &amp;lg );
    if (nGroupId==-1)
        return nGroupId;
 
    // Insert all current items into this group
    for(int nRow = 0; nRow &lt; GetItemCount(); ++nRow)
    {
        LVITEM lvItem = {0};
        lvItem.mask = LVIF_GROUPID;
        lvItem.iItem = nRow;
        lvItem.iSubItem = 0;
        lvItem.iGroupId = nGroupID;
        SetItem( &amp;lvItem );
    }
}</pre>
 
<p>The above example code creates a new group with the following properties:</p>
 
<ul>
<li>The group will be inserted at <code>nIndex</code> in the <code>CListCtrl</code> internal list of groups.</li>
 
<li>The group will get the external identifier <code>nGroupId</code>.</li>
 
<li>The group headline will become the text-string <code>strHeader</code>.</li>
</ul>
 
<h2>Limitations in Windows XP</h2>
 
<p>When working with groups on Windows XP, we will discover the following are missing:</p>
 
<ul>
<li>It is not possible to ask how many groups there are in the <code>CListCtrl</code> internal list of groups. Instead, it is recommended to keep track of the created groups ourselves.</li>
 
<li>It is not possible to iterate over the groups in the <code>CListCtrl</code> internal list of groups. Instead, it is recommended to keep track of the created groups ourselves.</li>
 
<li>It is not possible to ask the <code>CListCtrl</code> if the mouse cursor is currently over a group. Instead, we have to do a lot of guessing.</li>
 
<li>It is not possible to change the group state, so it becomes collapsed.</li>
</ul>
 
<p>These limitations have been solved with Windows Vista, and at the same time, the following features have been added:</p>
 
<ul>
<li>Can attach a task-link to the group</li>
 
<li>Can provide a subtitle-text that is placed just below the header-text</li>
 
<li>Can provide a footer-text to the group</li>
</ul>
 
<h2>Using the Source Code</h2>
 
<p>The source code provided demonstrates how to activate the different grouping features:</p>
 
<ul>
<li><strong><code>InsertGroupHeader()</code></strong> - Creates a new group. Wrapper around <code>CListCtrl::InsertGroup()</code>.</li>
 
<li><strong><code>SetRowGroupId()</code></strong> - Adds a row to an existing group. Wrapper around <code>CListCtrl::SetItem()</code> with <code>LVIF_GROUPID</code>.</li>
 
<li><strong><code>GroupByColumn(int nCol)</code></strong> - Creates a new group for each unique cell text in the specified column.</li>
 
<li><strong><code>SortColumn(int nCol)</code></strong> - Sorts the groups generated from the specified column. Wrapper around <code>CListCtrl::SortGroups()</code>.</li>
 
<li><strong><code>GroupHitTest(const CPoint&amp; point)</code></strong> - Attempts to find the group below the given mouse point.</li>
 
<li><strong><code>CheckEntireGroup()</code></strong> - When having the <code>CListCtrl</code> extended style <code>LVS_EX_CHECKBOXES</code> enabled, this method will change the check box state of an entire group.</li>
</ul>
 
<p>It also demonstrates how to use some of the new Windows Vista features:</p>
 
<ul>
<li><strong><code>CollapseAllGroups()</code></strong> - Loops through all the groups and makes them collapse. Wrapper around <code>CListCtrl::SetGroupInfo()</code> with <code>LVGS_STATE</code>.</li>
 
<li><code><strong>SetGroupTask()</strong></code> - Changes the task-link of a group. When the user clicks the task link, it will generate a <code>LVN_LINKCLICK</code> message.</li>
 
<li><code><strong>SetGroupSubtitle()</strong></code> - Changes the subtitle of a group.</li>
 
<li><code><strong>SetGroupFooter()</strong></code> - Changes the footer of a group.</li>
</ul>
 
<h2>History</h2>
 
<ul>
<li><strong>2008-09-16</strong> - First release of the article</li>
 
<li><strong>2009-09-28</strong> - Backport of bug-fixes from <code>CGridListCtrlEx</code>, and at startup it now groups the rows by the 3<sup>rd</sup> column</li>

<li><strong>2011-07-27</strong> - Fixed bug in GroupHitTest() when used on Vista\Win7 and compiled with _WIN32_WINNT >= 0x0600</li>
</ul>
 
</span>
<!-- End Article -->

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Denmark Denmark
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions