Microsoft's CListCtrl
has support for displaying data in a grid
using the report style, but one have to make several changes to implement
features like:
This article will demonstrate a customized CListCtrl
, which
implements all the above features, while maintaining the Windows XP/Vista look.
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:
CListCtrl
, so applications will not get the benefit
of the improvements Microsoft adds to the CListCtrl
.
LVS_OWNERDATA
that makes sorting a little harder.CListCtrl
,
but hard to add new ways to display data, and it tries to store a copy of the
entire datamodel inside itself.
CEdit
,
and also misses subitem navigation.Want a CListCtrl
that is using custom drawing (not owner drawing),
and at the same time doesn't try to interfere with the normal item drawing.
Hopefully such a CListCtrl
will not be broken in case Microsoft
extends their CListCtrl
.
The CGridListCtrlEx
tries to stay true to the CListCtrl
,
and doesn't try replace anything the CListCtrl
already provides.
This means one can replace a CListCtrl
with CGridListCtrlEx
without needing to do anything more.
It is recommended that one doesn't use the CGridListCtrlEx
directly,
but makes one own class that inherits/derives from CGridListCtrlEx
.
This will make it easier to migrate any updates there will be to the CGridListCtrlEx
class later.
By default when inserting columns in the CGridListCtrlEx
, then they
will be configured as readonly without the ability to be edited. By using CGridListCtrlEx::InsertColumnTrait()
then one 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, then 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
datamodel.
By using CGridListCtrlEx::InsertColumnTrait()
then one can also
provide a CGridColumnTrait
class which works as an 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);
One can specify the items of the combo-box when inserting the columns (as shown
above). If wanting to provide the combobox items dynamically, then one can
override the CGridListCtrlEx::OnTraitEditBegin()
, and then either
use dynamic_cast<>
or use the CGridColumnTraitVisitor
to modify the items in the combobox.
By default the GridListCtrlEx
will have sorting enabled for all
columns, where it will perform a simple text-comparison. If wanting more
advanced sorting, then one 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.
By default the CGridListCtrlEx
will just display the cell contents
as tooltip. If wanting to display something different in the tooltip, then one
can override the CGridListCtrlEx::GetCellTooltip()
method.
If wanting to change the foreground/background color or the font style (bold,
italic, underline), then one can override the CGridListCtrlEx::GetCellCustomColor()
and CGridListCtrlEx::GetCellCustomFont()
.
CGridListCtrlEx
tries to keep away from all the nasty details about
how to display and edit data. Instead this is handled by the CGridColumnTrait
class, and if wanting to modify how data is displayed, then it is
"just" a matter of creating a new CGridColumnTrait
class.
When inserting a column, then one can assign a CGridColumnTrait
to
the column. The CGridListCtrlEx
will activate the appropriate CGridColumnTrait
when needing 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 one can easily add extra properties to a column.
When inheriting from CGridColumnTrait
, then one must consider the
following:
LVN_ENDLABELEDIT
message when edit
is complete.
The 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
- Implement cell editing with CComboBox
.CGridColumnTraitVisitor
- Visitor pattern if wanting to add new
behavior to the column-traits.
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.
LVS_EX_SUBITEMIMAGES
, as subitem images now
overlaps the grid-borders (Bug in CListCtrl
).
Only the group-style handling should be part of the
CGridListCtrlEx
itself, while the other features should be handled
with new specialized CGridColumnTrait
's.