Click here to Skip to main content
15,885,546 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 241K   8.7K   120  
Example of how to enable categories in the MFC list control
<ul class="download"><li>
		<a href="CListCtrl_ToolTip/ListCtrl_Tooltip.zip">Download source code - 200 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&nbsp; <code>CListCtrl</code>.</p>

<p>The demo application allows you to experience the how grouping can be used. Just 
	right-click a column header, to group the data according to that header.&nbsp;</p>
<p><img height="254" width="471" alt="screenshot.png" src="CListCtrl_Grouping/screenshot.png" /></p>
<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="../../KB/list/GroupListView.aspx">ListView Grouping 
			XP Style</a>

	</li><li>
		<a href="../../KB/list/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">
		MSDN - Windows Vista Control Enhancements</a>, which describes some of the 
	new stuff in Windows Vista.
</p>
<p>The first time I actually saw an useful application make use of this grouping 
	feature was with <a href="http://tortoisesvn.tigris.org/tsvn_1.5_releasenotes.html#changelist-support">
		TortoiseSVN 1.5</a>.</p>

<h2>How to activate grouping in CListCtrl</h2>
<p>Before grouping can be activated, then some things has to be in order:</p>
<ul><li>
	The operating system must support common controls ver. 6 (Windows XP/Vista and 
	newer)
	&nbsp;</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, then one can create 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;
		return SetItem( &amp;lvItem );
	}
}
</pre>
<p>
	The above example code create 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>Limititations in Windows XP</h2>
<p>When working with groups on Windows XP, then one will discover the following is 
	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 one have to do a lot of guessing.
	</li><li>
		It is not possible to change the group state, so it become 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&nbsp;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> -&nbsp;Adds a row to an existing group. Wrapper around 
	&nbsp;<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.
	&nbsp;</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.
	&nbsp;</li><li>
		<strong><code>CheckEntireGroup()</code></strong> - When having the <code>CListCtrl</code> extended style <code>LVS_EX_CHECKBOXES</code> 
		enabled, then this method will change the check box state of&nbsp;an entire 
		group.&nbsp;</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><strong></strong> - Changes the task-link of a group. When the user clicks the 
	task link then it will generate a <code>LVN_LINKCLICK</code> message.
	</li><li>

	<code><strong>SetGroupSubtitle()</strong></code><strong></strong> - Changes the subtitle of a group.
	</li><li><strong>
		</strong><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></ul>

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