5,660,782 members and growing! (20,276 online)
Email Password   helpLost your password?
Desktop Development » List Controls » Custom Draw     Intermediate License: The Code Project Open License (CPOL)

CGridListCtrlEx - Grid Control Based on CListCtrl

By Snakefoot

A custom draw CListCtrl with subitem editing and formatting
C++, Windows, Dev

Posted: 3 Sep 2008
Updated: 9 Nov 2008
Views: 20,951
Bookmarked: 56 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
18 votes for this Article.
Popularity: 5.52 Rating: 4.39 out of 5
2 votes, 11.1%
1
0 votes, 0.0%
2
1 vote, 5.6%
3
2 votes, 11.1%
4
13 votes, 72.2%
5

Introduction

Microsoft's CListCtrl has support for displaying data in a grid using the report style, but we have to make several changes to implement features like:

This article demonstrates how to use CGridListCtrlEx, which implements all the above features while maintaining the Windows XP/Vista look.

screenshot.png

The Google Code - CGridListCtrlEx can be used if wanting SubVersion access.

Background

There are lots of advanced grid controls that extend the CListCtrl, and one of those is the Enhanced List Control (CGfxListCtrl). This wonderful control provides all the above features, but fails to handle Windows XP and Vista. Finding a good replacement for this control is not very easy:

  • MFC Grid Control - Doesn't inherit from CListCtrl, so applications will not get the benefit of the improvements Microsoft adds to the CListCtrl.
  • CQuickList - Very close to being a perfect replacement, but hard to add new ways to display data, and it requires LVS_OWNERDATA that makes sorting a little harder.
  • XListCtrl - Also a very complete CListCtrl, but hard to add new ways to display data, and it tries to store a copy of the entire data model inside itself.
  • Another Report List Control - Simple and easy to use, but lacks other means to edit data besides using CEdit, and also misses subitem navigation.

The CGridListCtrlEx tries to be simple, while still providing the ability to customize how a cell should be displayed and edited. In case Microsoft extends their CListCtrl again, then hopefully, the core of CGridListCtrlEx will continue to function.

How to Use the CGridListCtrlEx

The CGridListCtrlEx tries to stay true to the CListCtrl, and doesn't try to replace anything the CListCtrl already provides. This means we can replace a CListCtrl with CGridListCtrlEx without needing to do anything more.

It is recommended that we don't use the CGridListCtrlEx directly, but create a new class that inherits/derives from CGridListCtrlEx. This will make it easier to migrate any updates there will be to the CGridListCtrlEx class later on.

Editing Cells/Subitems

By default, when inserting columns in the CGridListCtrlEx, they will be configured as read-only, without the ability to be edited. By using CGridListCtrlEx::InsertColumnTrait(), we can provide a CGridColumnTrait class which specifies what type of editor it should use.

CGridColumnTrait* pTrait = new CGridColumnTraitEdit;
m_ListCtrl.InsertColumnTrait(nCol, title.c_str(), LVCFMT_LEFT, 100, nCol, pTrait);

When having edited an item, a standard LVN_ENDLABELEDIT message will be sent to the CListCtrl. When the CGridListCtrlEx receives this message, it will automatically call the virtual method CGridListCtrlEx::OnTraitEditComplete(), allowing a derived class to validate the input and maybe update an underlying data model.

Editing Cells/Subitems with a Combo-box

By using CGridListCtrlEx::InsertColumnTrait(), we can also provide a CGridColumnTrait class which works as a CComboBox.

CGridColumnTraitCombo* pTrait = new CGridColumnTraitCombo;
pTrait->AddItem(0, "Hello");
pTrait->AddItem(1, "Goodbye");
m_ListCtrl.InsertColumnTrait(nCol, title.c_str(), LVCFMT_LEFT, 100, nCol, pTrait);

We can specify the items of the CComboBox when inserting the columns (as shown above). If we want to provide the CComboBox items dynamically, then we can override the CGridListCtrlEx::OnTraitEditBegin(), and then either use dynamic_cast<> or use the CGridColumnTraitVisitor to modify the items in the CComboBox.

Sorting Rows

By default, the GridListCtrlEx will have sorting enabled for all columns, where it will perform a simple text-comparison. If we want a more advanced sorting, then we can override the CGridListCtrlEx::SortColumn() method. Then, it is just a matter of choosing the right way to perform the sorting. See CListCtrl and Sorting Rows.

Showing Tooltip

By default, the CGridListCtrlEx will just display the cell contents as tooltip. If we want to display something different in the tooltip, then we can override the CGridListCtrlEx::OnDisplayCellTooltip() method.

Formatting Cells/Subitems

If we want to change the foreground/background color or the font style (bold, italic, underline), then we can override the methods CGridListCtrlEx::OnDisplayCellColor() and CGridListCtrlEx::OnDisplayCellFont().

Displaying Cell/Subitem Images

The CGridListCtrlEx enables the extended style LVS_EX_SUBITEMIMAGES by default, but one is still required to attach a CImageList using CListCtrl::SetImageList().

After having attached the images, one can bind a cell/subitem with an index in the CImageList. This can be done with CGridListCtrlEx::SetCellImage(), or if using I_IMAGECALLBACK then return the image index by overriding CGridListCtrlEx::OnDisplayCellImage().

The CGridListCtrlEx also enables the extended style LVS_EX_GRIDLINES by default, which can cause subitem images to overlap the grid border. This can be solved by making sure that the image only uses 15 of the 16 pixels (first pixel transparent).

When using subitem images and running the application on Windows XP or using classic style, it will show a white background when a row is selected. This can be fixed by using CGridRowTraitXP:

m_ListCtrl.SetDefaultRowTrait(new CGridRowTraitXP);

Changing Row Height

The CGridListCtrlEx uses customdraw, so there are only these available solutions:

  • Assign a CImageList where the image has the height wanted for the row.
  • Change the font of the grid control, and the row height will follow. CGridListCtrlEx::SetCellMargin() uses this trick to increase the font of the grid control, while keeping the row font intact.

Changing the Empty Markup Text

When the CGridListCtrlEx doesn't contain any items, it will display markup text to indicate the list is empty.

Use CGridListCtrlEx::SetEmptyMarkupText() to change this markup text. If providing empty text, then it will behave like a normal CListCtrl.

If using CGridListCtrlGroups, it will instead react to LVN_GETEMPTYMARKUP if running on Windows Vista.

How Does the CGridColumnTrait Work

CGridListCtrlEx tries to keep away from all the nasty details about how to display and edit data. These things are instead handled by the CGridColumnTrait class, and if we want to modify how data is displayed, then it is "just" a matter of creating a new CGridColumnTrait class.

When inserting a column, we can assign a CGridColumnTrait to the column. The CGridListCtrlEx will activate the appropriate CGridColumnTrait when we need to draw a cell in that column, or edit a cell in the column.

The CGridColumnTrait includes some special members known as meta-data. These members can be used by your own class when it derives from CGridListCtrlEx, so we can easily add extra properties to a column.

When inheriting from CGridColumnTrait, we must consider the following:

  • If performing custom drawing, then we must also handle the selection and focus coloring.
  • If performing editing, then we must ensure that the editor closes when it loses focus, and also sends a LVN_ENDLABELEDIT message when the edit is complete.

How Does the CGridRowTrait Work

It is based on the same idea as CGridColumnTrait but operates at row level instead of column level. This is useful for situations where one has to modify the display behavior of all columns.

Using the Code

The source code includes the following classes:

  • CGridListCtrlEx - The specialized CListCtrl
  • CGridListCtrlGroups - CGridListCtrlEx extended with support for grouping
  • CGridColumnTrait - Specifies the interface of a column-trait
    • CGridColumnTraitText - Implements cell formatting
      • CGridColumnTraitEdit - Implements cell editing with CEdit
      • CGridColumnTraitCombo - Implements cell editing with CComboBox
      • CGridColumnTraitDateTime - Implements cell editing with CDateTimeCtrl
  • CGridRowTrait - Specifies the interface of a row trait
    • CGridRowTraitText - Implements row formatting
    • CGridRowTraitXP - Implements drawing of subitem image background when using classic- or XP-style

Things To Do

The CGridListCtrlEx tries to stay away from performing any drawing itself. This means that the following features/bugs will not get that much attention:

  • Support for checkboxes - Requires a CGridColumnTrait class that draws the entire cell. Maybe consider some misuse of the iImage property of LV_ITEM to store the checkbox state.
  • Support for progress bar - Requires a CGridColumnTrait class that draws the entire cell.

Implementing a CGridColumnTrait class that draws the entire cell could probably be done by stealing/borrowing some code from ListCtrl - A WTL List Control with Windows Vista Style Item Selection.

Contributions to this project are very welcome.

History

  • 2008-09-04 - First release of the article
  • 2008-09-10 - Improved grid-cell editor support
    • Added ability to add extra cell margin with CGridListCtrlEx::SetCellMargin()
    • Better resizing of grid-cell editors according to font
    • Extended CComboBox editor to handle CBS_DROPDOWN style (earlier, it only supported CBS_DROPDOWNLIST) - credits Chris Maunder
    • Added CDateTimeCtrl editor
  • 2008-09-18 - Added support for grouping with CGridListCtrlGroups
    • Fixed drawing bugs when using Classic- and XP-style
      • Fixed image background color for selected subitems (no longer white)
      • Fixed grid border disappearing when scrolling right and left
      • Indicate the list is empty when it contains no items
    • Extended CComboBox editor, so it automatically resizes dropdown width to its contents
  • 2008-09-24
    • Replaced the CGridListCtrlXP with CGridRowTraitXP
    • Fixed some reported bugs
  • 2008-09-26
    • Fixed extended style when used in CView
    • Fixed positioning of context-menu when using keyboard shortcut (SHIFT+F10)
  • 2008-10-09
    • Fixed compiler errors that appeared when using Visual Studio 6 (VC6)
  • 2008-11-07
    • Added clipboard support for copying the contents of the selected cell / rows
    • Renamed the "Callback"-functions to "OnDisplay", as it resembles the MFC naming convention
    • Fixed some reported bugs

License

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

About the Author

Snakefoot



Location: Denmark Denmark

Other popular List Controls articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 37 (Total in Forum: 37) (Refresh)FirstPrevNext
GeneralCGridColumnTraitDateTime - cell editingmemberMember 21683021:28 18 Nov '08  
GeneralRe: CGridColumnTraitDateTime - cell editingmemberSnakefoot2:44 18 Nov '08  
GeneralRe: CGridColumnTraitDateTime - cell editingmemberMember 216830223:57 18 Nov '08  
GeneralRe: CGridColumnTraitDateTime - cell editingmemberSnakefoot14hrs 21mins ago 
GeneralRe: CGridColumnTraitDateTime - cell editingmemberMember 216830212hrs 52mins ago 
GeneralRe: CGridColumnTraitDateTime - cell editingmemberSnakefoot12hrs 23mins ago 
Generalhave a bugmemberdenytrans17:08 29 Oct '08  
GeneralRe: have a bugmemberSnakefoot23:27 29 Oct '08  
GeneralRe: have a bugmemberSnakefoot23:45 2 Nov '08  
Questionnot work in vc6memberilovedrv16:49 7 Oct '08  
AnswerRe: not work in vc6memberSnakefoot0:10 8 Oct '08  
GeneralCGridListCtrlEx in CView derived classmember_Manuel6:19 20 Sep '08  
GeneralRe: CGridListCtrlEx in CView derived classmemberSnakefoot11:29 20 Sep '08  
QuestionRe: CGridListCtrlEx in CView derived classmemberAeluin17:41 21 Sep '08  
AnswerRe: CGridListCtrlEx in CView derived classmemberSnakefoot2:52 26 Sep '08  
QuestionBug? or something should be modified before Create?memberAeluin16:38 18 Sep '08  
AnswerRe: Bug? or something should be modified before Create?memberSnakefoot17:08 18 Sep '08  
GeneralRe: Bug? or something should be modified before Create?memberAeluin18:00 18 Sep '08  
GeneralRe: Bug? or something should be modified before Create?memberSnakefoot23:44 18 Sep '08  
GeneralRe: Bug? or something should be modified before Create?memberSnakefoot2:23 19 Sep '08  
GeneralA little bugmembervcforever22:38 15 Sep '08  
GeneralRe: A little bugmemberSnakefoot22:47 15 Sep '08  
GeneralRe: A little bugmembervcforever23:36 15 Sep '08  
GeneralRe: A little bugmemberSnakefoot5:47 16 Sep '08  
GeneralRe: A little bugmemberSnakefoot0:50 18 Sep '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 9 Nov 2008
Editor: Deeksha Shenoy
Copyright 2008 by Snakefoot
Everything else Copyright © CodeProject, 1999-2008
Web15 | Advertise on the Code Project