Click here to Skip to main content
15,920,596 members
Articles / Desktop Programming / MFC

Another Report List Control

Rate me:
Please Sign up or sign in to vote.
4.89/5 (95 votes)
31 Dec 20036 min read 1.3M   17.4K   235   178
A report style CListCtrl supporting sorting, sub-item editing, sub-item image, sub-item color etc.


By seeing how widely "Report List Controls" are used in various applications, it is really needless to introduce what list controls are and what report style is, so I will just skip "what it is" and come right to "what it does".


Item Sorting

When the user left-clicks on a column header, or the developer issues a call to CReportCtrl::SortItems, a whole column of items are sorted. Their text formats will be recognized appropriately (decimal numeric, hex numeric, decimal points, percentages, date & time, plain text) and sorted accordingly.

A message WM_ITEM_SORTED is sent to the parent window after a sorting is completed, the column index is passed as wParam and sorting method is passed as lParam (0=descending, 1=ascending).

Related Methods:
BOOL IsSortable() const; // Is sort allowed?
BOOL SetSortable(BOOL bSet); // Allow/disallow sorting
BOOL IsSortAscending() const;
int GetSortedColumn() const;
// Sort a specified column.
void SortItems(int nColumn, BOOL bAscending); 

Item Sort-Separator

Sometimes you may not want a whole column to be sorted altogether, rather, you want them to act like multiple parts so that each part of items are sorted internally whereas parts themselves remain unaltered. Please imagine this scenario, you are using the control to display an audit report table, all rows are numeric values and the last row is the sum of all above values; now if the user sorts the column in descending order, the row which contains the sum-value will be moved to the top because basically the sum-value will most likely be greater than any other value. That's NOT what you want, you would like the sum row always stay on the bottom of the table, right? Now you would wish there's a way to insert some kind of a "separator" between the sum row and all other data rows, so the sorting would never affect the sum row. How to do that? Easy, use CReportCtrl::SetSortSeparator.

Below is an unsorted table, I want the 3 parts (blue, green, yellow) to be sorted separately:


Sort it without using any separator:

m_wndList.SetSortSeparator(NULL); // Disable sort-separator
// Sort the first column in ascending order
m_wndList.SortItems(0, TRUE);

sorted without using separator

See how the table became a mess and the 3 parts got broken up, that's not what we wanted. But if at the above step, you used sort-separator instead:

// m_wndList.SetSortSeparator(NULL); // Disable sort-separator
// m_wndList.SortItems(0, TRUE); // Sort the first column in ascending order

// Use string "Separator" as the sort-separator
// Sort the first column in ascending order
m_wndList.SortItems(0, TRUE);

Sample screenshot

Now it's nice, the 3rd image is exactly what we were expecting.

Related Methods:
void SetSortSeparator(LPCTSTR lpSortSeparator);
LPCTSTR GetSortSeparator() const;

Sub-item Text Editing

When the user double-clicks on a grid, or left-clicks on a grid which previously had selection mark and focus, or the developer issues a call to CReportCtrl::StartEdit, the item text of that sub-item becomes editable.

While the item text is being edited, if the user clicks anywhere other than the under-editing-grid in the control, or presses the "Esc" key, or presses the "Enter" key, or the developer issues a call to CReportCtrl::EndEdit, the item editing is ended and changes made will either be committed or cancelled, depending on the action types which ended the editing.

Related Methods:
BOOL IsEditable() const; // Is Item text editable?
void SetEditable(BOOL bSet = TRUE); // Allow item text editting

// Display the editbox, previous edit are committed
BOOL StartEdit(int nItem, int nSubItem); 

BOOL EndEdit(BOOL bCommit = TRUE); // Commit/cancel text edit, hide the editbox
CEdit* GetEditControl();

Customizing Checkbox Styles

Checkboxes inside a report list control are useful but I often found that I really need to get a little more hold of them, for example, sometimes I want to be notified when the user clicks on a checkbox, or I want to make the checkboxes read-only so that users cannot alter the checked/unchecked value of the checkboxes by inputs. These could be quite tricky to achieve in a plain MFC CListCtrl, but became a piece of cake in this class.

Checkbox styles can be specified by calling CReportCtrl::SetCheckboxeStyle. Recognizable styles are:

  • RC_CHKBOX_NONE -- No checkbox displayed
  • RC_CHKBOX_NORMAL -- Normal style, multiple check marks allowed
  • RC_CHKBOX_SINGLE -- Single check only. Checkboxes are mutually exclusive, just like using radio buttons.
  • RC_CHKBOX_DISABLED -- Disabled, cannot be checked/unchecked by user input.

A message WM_ON_CHKBOX is sent to the parent window whenever the user clicks on the checkbox of a list item. The item index is passed as wParam and the mouse event (Such as WM_LBUTTONDOWN, WM_RBUTTONDOWN, etc.) is passed as lParam.

Related Methods:
void SetCheckboxeStyle(int nStyle = RC_CHKBOX_NORMAL); // Set checkbox styles.
int GetCheckboxStyle() const;
// Example:
// Make the checkbox read-only

Sub-item Images & Sub-item Colors

Each grid can have its own image, text color and background color. To use images, you need to first call CReportCtrl::SetImageList to specify an image list or a bitmap resource ID.

Related Methods:
// Column header images
BOOL SetHeaderImage(int nColumn, int nImageIndex, BOOL bLeftSide = TRUE);
int GetHeaderImage(int nColumn) const;
CImageList* SetHeaderImageList(UINT nBitmapID, COLORREF crMask = RGB(255, 0, 255));
CImageList* SetHeaderImageList(CImageList* pImageList);
// Sub-item images
BOOL SetItemImage(int nItem, int nSubItem, int nImageIndex);
int GetItemImage(int nItem, int nSubItem) const;
CImageList* SetImageList(UINT nBitmapID, COLORREF crMask = RGB(255, 0, 255));
CImageList* SetImageList(CImageList* pImageList);
CImageList* GetImageList() const;
// Sub-item Text & Background Color
void SetItemTextColor(int nItem = -1, int nSubItem = -1, 
COLORREF GetItemTextColor(int nItem, int nSubItem) const;
void SetItemBkColor(int nItem = -1, int nSubItem = -1, 
COLORREF GetItemBkColor(int nItem, int nSubItem) const;
// Example: Set image and color for grid - 1st row 3rd column

m_wndList.SetImageList(IDB_BITMAP1); // Using bitmap resource "IDB_BITMAP1"
m_wndList.SetItemImage(0, 2, 0); // Set the 1st row 3rd column with image index 0

// Set grid colors
m_wndList.SetItemTextColor(0, 2, RGB(255, 0, 0), TRUE); // Grid text color: red
m_wndList.SetItemBkColor(0, 2, RGB(0, 255, 0), TRUE); // Grid bkground color: green

Convenient Item Operating

List item operations are made very simple and intuitive, you can select/unselect, check/uncheck, delete items which match a given state or a combination of given states. Every list item may have one or more of the following states:

  • RC_ITEM_ALL - All items regardless of states
  • RC_ITEM_SELECTED - Selected items
  • RC_ITEM_UNSELECTED - Unselected items
  • RC_ITEM_CHECKED - Checked items
  • RC_ITEM_UNCHECKED - Unchecked items
  • RC_ITEM_FOCUSED - Focused item
  • RC_ITEM_UNFOCUSED - Unfocused items

Multiple states can be combined using the "|" operator. Note that in any combination of states, if RC_ITEM_ALL is present, then all other states will be ignored and the state examination will always return TRUE.

Related Methods:
int GetFirstItem(DWORD dwStates = RC_ITEM_ALL, int nStartAfter = -1) const;
int GetLastItem(DWORD dwStates = RC_ITEM_ALL, int nStartBefore = -1) const;
int GetItemCount(DWORD dwStates = RC_ITEM_ALL) const; 
DWORD GetItemStates(int nItem) const;
BOOL ExamItemStates(int nItem, DWORD dwStates) const;
BOOL SetItemStates(int nItem, DWORD dwNewStates);
int SetAllItemStates(DWORD dwOldStates, DWORD dwNewStates);
void InvertItems(int nType); // RC_INVERT_SELECTION or RC_INVERT_CHECKMARK
// Example:

// Select all items which were unselected and unchecked

// How many items are not checked?
int n = m_wndList.GetItemCount(RC_ITEM_UNCHECKED);

//Unselect and check all items regardless of their previous states

// Delete all items which were selected and checked

Convenient Item Positioning

Item position manipulations are extensively implemented in this class, you can easily move items up or down, or to a particular position, or swap 2 existing items, etc. The following member functions are designed for this kind of operations:

int MoveUp(int nItem, int nCount = 1); // Move an item upwards by "nCount" positions.

// Move an item downwards by "nCount" positions.
int MoveDown(int nItem, int nCount = 1); 

int MoveToTop(int nItem); // Move an item up to the top.
int MoveToBottom(int nItem); // Move an item down to the bottom.
int MoveTo(int nItem, int nNewPosition); // Move an item to a particular position 
BOOL SwapItems(int nItem1, int nItem2); // Swap two items including all attributes.

Item Text Operations

CListCtrl::SetItemText is one of the most frequently utilized functions of CListCtrl. However, it only accepts string parameters. So if we want to display some other data types, we must first convert them into string representation, but in this class we are freed from doing such a chore.

BOOL SetItemText(int nItem, int nSubItem, INT val);
BOOL SetItemText(int nItem, int nSubItem, UINT val);
BOOL SetItemText(int nItem, int nSubItem, LONG val);
BOOL SetItemText(int nItem, int nSubItem, ULONG val);
BOOL SetItemText(int nItem, int nSubItem, TCHAR val);
BOOL SetItemText(int nItem, int nSubItem, DOUBLE val, int nPrecision = -1);
BOOL SetItemText(int nItem, int nSubItem, 
   const COleDateTime& dateTime, 
   DWORD dwFlags = 0);

How to Use in a Dialog Based Application

To use the class, you need to add ReportCtrl.h and ReportCtrl.cpp into your workspace and include ReportCtrl.h where needed. To create an instance of CReportCtrl, you may either draw a CListCtrl on your dialog and assign a CReportCtrl type to it using class wizard, or manually declare a CReportCtrl variable and create the control window at runtime using CReportCtrl::Create.

How to Use in a List View

I often heard someone ask "Hey this control works great in a dialog based app, but how can I use it in a CListView"? Well, the answer is you don't, instead, you should let your view derive from CFormView, not CListView, then put a list control on your form view and make the control derive from CReportCtrl. Then add one single line of code to your view class' OnSize function:

void CMyView::OnSize(UINT nType, int cx, int cy) 
    CFormView::OnSize(nType, cx, cy);

    // TODO: Add your message handler code here
    m_wndList.ResizeToFitParent(); // Add this line!

And that's it, whenever your view resizes, the list control will automatically resize itself to occupy the whole client area of your view, that's exactly what a CListView looks like.


Dec. 2nd, 2003

  • Initial release.

Dec. 3rd, 2003

  • Fixed a bug in EndEdit where item text was not properly committed.
  • Completed the implementation of the "Sort-Separator" feature.
  • Updated source and demo project file downloads.

Jan. 01, 2004

  • Fixed a bug in SetItemData.
  • Added message WM_EDIT_COMMITTED which is sent to the parent window when an item text editing is committed.
  • Fixed a bug in SetItemText(double type).
  • Fixed a bug where item sorting does not work properly when there are multiple CReportCtrl objects on same window.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

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

Comments and Discussions

QuestionI Got an Error Pin
Member 1107371410-Sep-14 22:28
Member 1107371410-Sep-14 22:28 
Questionimage on the checkbox Pin
P Uday kishore18-Jun-13 1:01
professionalP Uday kishore18-Jun-13 1:01 
QuestionHow to change subitem image when user click on cell to edit it Pin
Member 3436247-Oct-12 4:46
Member 3436247-Oct-12 4:46 
GeneralGrid redraw using different fonts Pin
Member 440527719-Sep-10 9:49
Member 440527719-Sep-10 9:49 
GeneralSort function fixed Pin
Member 440527719-Sep-10 9:45
Member 440527719-Sep-10 9:45 
GeneralNot properly working with thread and problem in show hide List. Pin
Le@rner2-Sep-10 21:03
Le@rner2-Sep-10 21:03 
GeneralMy vote of 5 Pin
leanoson20-Jul-10 21:34
leanoson20-Jul-10 21:34 
QuestionHow to handle two (or more) report lists Pin
Rik_Sal31-May-10 5:20
Rik_Sal31-May-10 5:20 
GeneralError : m_wndList.Create(this, 0, NULL, 0); Pin
D.Manivelan3-May-10 19:33
D.Manivelan3-May-10 19:33 
Generaladd CCombo? 请问如何在这个listctrl里面添加combo控件 Pin
freshlover7-Feb-10 22:44
freshlover7-Feb-10 22:44 
Generalstudy again Pin
haihui5-Nov-09 18:27
haihui5-Nov-09 18:27 
Generalstudying Pin
haihui5-Nov-09 18:20
haihui5-Nov-09 18:20 
Questionlistview is wrong. Pin
andywung21-Sep-09 22:53
andywung21-Sep-09 22:53 
Questionhow to create in cview or scrollview ? Pin
rambojanggoon21-Sep-09 15:06
rambojanggoon21-Sep-09 15:06 
GeneralHigh resolution image list Pin
mohammadmot8-Sep-09 23:09
mohammadmot8-Sep-09 23:09 
QuestionIs it thread safe? Pin
Sunny12709-Jun-09 22:50
Sunny12709-Jun-09 22:50 
AnswerRe: Is it thread safe? Pin
bbyl20495-Aug-09 16:46
bbyl20495-Aug-09 16:46 
GeneralRe: Is it thread safe? Pin
Sunny12709-Aug-09 1:14
Sunny12709-Aug-09 1:14 
GeneralThanks! Pin
ianleelj19-Nov-08 18:56
ianleelj19-Nov-08 18:56 
GeneralVery Clear And Very Easy Pin
Li Shu23-Oct-08 17:06
Li Shu23-Oct-08 17:06 
Generaleasy to get working thank you Pin
mvno17-Aug-08 10:24
mvno17-Aug-08 10:24 
Questionhow to add my own bitmap? Pin
www216-Jul-08 21:48
www216-Jul-08 21:48 
GeneralAction After Editing Pin
Member 12142495-Jun-08 6:25
Member 12142495-Jun-08 6:25 
Generalno Pin
friendwaters28-May-08 22:54
friendwaters28-May-08 22:54 
GeneralPatch to allow sorting by monetary value Pin
atlas319-May-08 5:10
atlas319-May-08 5:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.