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:
-
Sorting
-
Cell navigation and keyboard search
-
Tooltips
-
Hiding and showing columns
-
Cell editing
This article
will demonstrate a customized
CListCtrl
,
which implements all the above features,
while maintaining the Windows XP/Vista
look.
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
Grid
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
grid control
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
Library Source
Code. 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 combobox.
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 combobox
when inserting the columns (as shown
above). If we want to provide the
combobox 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 combobox.
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 Grid
Control 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::GetCellTooltip()
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::GetCellCustomColor()
and
CGridListCtrlEx::GetCellCustomFont()
.
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
Grid Contrl Library
CGridColumnTrait
class.
When inserting a column, we can assign a
Grid Contrl Library
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
Grid VC++ Source Code 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, we
must also handle the selection and
focus coloring.
-
If performing editing, we must
ensure that the editor closes when
it loses focus, and also sends a
LVN_ENDLABELEDIT
message when the edit is complete.
Using the Code
The VC++ source
code includes the following
classes:
CGridListCtrlEx
- The specialized
CListCtrl
CGridColumnTrait
- Specifies the interface of a
column-trait
CGridColumnTraitText
- Implements cell formatting
CGridColumnTraitEdit
- Implements cell editing
with
CEdit
CGridColumnTraitCombo
- Implements cell editing
with
CComboBox
CGridColumnTraitVisitor
- Visitor pattern if wanting to add
new behavior to the column-traits
Things To Do
The
CGridListCtrlEx
is not quite finished, as it still lacks
some features:
CListCtrl
group-style and the ability to group
rows according to a chosen column
-
Better handling of
LVS_EX_SUBITEMIMAGES
,
as subitem images now overlap the
grid-borders (bug in
CListCtrl
)
-
Support for checkboxes (might
consider some misuse of the
Image
property)
-
Support for progress bar
-
Support for date / time editing
Only the group-style handling should be
part of the
CGridListCtrlEx
itself, while the other features should
be handled with new specialized
CGridColumnTrait
s.