After pushing the CListCtrl to its limits in trying to display and edit
tabulated data I decided what was really needed was a dedicated grid control.
I started writing my own grid control from scratch but decided to save
time by modifying Joe Willcoxson's
free WorldCom grid control at
http://users.aol.com/chinajoe/wcmfclib.html. I tore apert his code and
rebuilt it from the ground up in order to get it to do all the things I needed.
The code has gone through so many modifications that I'm not sure if there is
even a single original line of code. In any case Joe's code was a great framework
on which to build.
The project started out as a simple clean up but very quickly ballooned
into a bit of a nightmare as I kept finding new features that I felt just
had to go into it. It has not been tested exhaustively - but I'm
fairly confident that it won't fall over too badly :). Joe was kind enough
to allow me to release the source with no strings attached (since it is
based on his code) but since the project was such a marathon I am placing
a couple of very minor conditions on the use of this code:
This file may be redistributed unmodified by any means PROVIDING
it is not sold for profit without the authors written consent, and providing
that this notice and the authors name and all copyright notices remains
intact. This code may be used in compiled form in any way you desire with
the following conditions. If the source code in this file is used in any
commercial application then a statement along the lines of "Portions copyright
(c) Chris Maunder, 1998-1999" must be included in the startup banner, "About"
box or printed documentation. The source code may not be compiled into
a standalone library and sold for profit. Besides - it's free to whoever
wants it anyway!
This software is provided "as is" without
express or implied warranty. Use it at your own risk!
Whilst I have made every effort to remove any undesirable "features",
I cannot be held responsible if it causes any damage or loss of time or
data.
Hopefully that isn't too much to ask considering the amount of work that
went into this. If you do use it in a commercial application then
please send me an email
letting me know. There's no point in me releasing and maintaining/upgrading
this thing if no one is gonna use it.
The control features:
Cell selection using the mouse, with optional Control and Shift key
combinations. Selection can be disabled.
Row and Column resizing. Sizing can be diabled for row, columns or both.
Auto row or column sizing when dividers are double-clicked.
Any number of fixed rows and columns.
Individual cells can have separate text and background colours.
Individual cells can have separate fonts.
Individaul cells can be marked "Read-Only", or have their modification status
set and checked.
OLE Drag and drop.
Ctrl-C, Ctrl-X and Ctrl-V perform clipboard copy, cut and paste, and Ctrl-A for
"Select All"
In place editing of cell contents. If a character key is pressed while
a cell has focus, editing will start on that cell, and the arrow keys
will allow navigation to other keys. If the current focus cell is clicked
on, editing will start and the arrow keys will move the carot inside the
edit control. Editing can be disabled.
Support for Microsoft intellimouse.
Optional grid lines.
Images in any cell
Full printing support, for either a Doc/View environment (inc Print
preview) or a standalone dialog based app (no print preview).
Optional "List mode", including full row selection, single row selection,
and sort on column header click.
Numerous virtual functions to allow this control to be extended very easily.
UNICODE support.
WinCE support
Titletips for cells that are too small to display their data.
Compiles under VC 4.2, 5.0, 6.0 and under the CE toolkit version 2.0 and 3.0
The sample project demonstrates most of the
features of the grid control.
The underlying class of the grid control is CGridCtrl which is
derived from CWnd. To use it, either use the MS Visual C++ dialog editor
to place a custom control on a dialog, and enter "MFCGridCtrl" (no quotes)
as the Class name, or use CGridCtrl::Create:
DDX_GridControl is used where a DDX_Control call is needed. It is necessary
to use DDX_GridControl instead of DDX_Control when creating the control via a
dialog template in order to ensure that the grid is correctly registered as a
drag and drop target. This is to avoid a strange COleDropTarget::Register
error that occurs in win95.
Sets the current image list for the grid. The control only
takes a copy of the pointer to the image list, not a copy of the list itself.
CImageList* GetImageList()
Gets the current image list for the grid.
void SetGridLines(int nWhichLines = GVL_BOTH)
Sets which (if any) gridlines are displayed.
See here for possible values.
int GetGridLines()
Gets which (if any) gridlines are displayed.
See here for possible return values.
void SetEditable(BOOL bEditable = TRUE)
Sets if the geid is editable.
BOOL IsEditable()
Gets whether or not the grid is editable.
void SetModified(BOOL bModified = TRUE,
int nRow = -1, int nCol = -1)
Sets the modified flag for a cell. If no row or columns is
specified, then change affects the entire grid.
BOOL GetModified(int nRow = -1, int nCol = -1)
Sets the modified flag for a cell, or if no cell, it returns
the status for the entire grid.
void SetListMode(BOOL bEnableListMode = TRUE)
Sets the grid into (or out of) List mode. When the grid is in list mode,
full row selection is enabled and clicking on the column header will sort the grid by rows.
BOOL GetListMode()
Get whether or not the grid is in list mode.
void SetSingleRowSelection(BOOL bSing = TRUE)
Sets the grid into (or out of) Single row selection mode. This mode
is only effective when in ListMode. When in this mode, only a single row at a time can
be selected, so the grid behaves somewhat like a multicolumn listbox.
BOOL GetSingleRowSelection()
Get whether or not the grid is in single row selection mode.
void EnableSelection(BOOL bEnable = TRUE)
Sets whether or not the grid cells can be selected.
BOOL IsSelectable()
Get whether or not grid cells are selectable.
void EnableDragAndDrop(BOOL bAllow = TRUE)
Sets whether drag and drop is enabled.
BOOL GetDragAndDrop()
Get whether drag and drop is allowed.
void SetRowResize(BOOL bResize = TRUE)
Sets whether or not rows can be resized.
BOOL GetRowResize()
Gets whether or not rows can be resized.
void SetColumnResize(BOOL bResize = TRUE)
Sets whether or not columns can be resized.
BOOL GetColumnResize()
Gets whether or not columns can be resized.
void SetHeaderSort(BOOL bSortOnClick = TRUE)
Sets whether or not rows are sorted on column header clicks in ListMode.
BOOL GetHeaderSort()
Gets whether or not rows are sorted on column header clicks in ListMode.
void SetHandleTabKey(BOOL bHandleTab = TRUE)
Sets whether or not the TAB key is used to move the cell selection.
BOOL GetHandleTabKey()
Gets whether or not the TAB key is used to move the cell selection.
void SetDoubleBuffering(BOOL bBuffer = TRUE)
Sets whether or not double buffering is used when painting (avoids flicker).
BOOL GetDoubleBuffering()
Gets whether or not double buffering is used when painting.
Sets the contents of a cell with the values from the
GV_ITEM structure. Note that the value
of the mask field will determine which values are actually changed
(cf. CListCtrl::SetItem).
BOOL GetItem(GV_ITEM* pItem)
Fills the GV_ITEM
structure with values from the specified cell. Note that the value of the
mask field will determine which values are actually retrieved
(cf. CListCtrl::GetItem).
BOOL SetItemText(int nRow, int nCol, LPCTSTR str)
Sets the text for the given cell. Returns TRUE on success
virtual CString GetItemText(int nRow, int nCol)
Gets the text for the given cell. This function is virtual
in order to aid extensibility. No more messing around with LVN_GETDISPINFO messages or
string pooling!
BOOL SetItemData(int nRow, int nCol, LPARAM lParam)
Sets the lParam (user-defined data) field for the given cell.
Returns TRUE on success. See also GV_ITEM.
LPARAM GetItemData(int nRow, int nCol) const
Gets the lParam (user-defined data) field for the given cell.
See also GV_ITEM.
BOOL SetItemImage(int nRow, int nCol, int iImage)
Sets the image index for the given cell. Returns TRUE on success.
See also GV_ITEM.
int GetItemImage(int nRow, int nCol) const
Gets the image index for the given cell.
BOOL SetItemState(int nRow, int nCol, UINT state)
Sets the state of the given cell. Returns TRUE on success.
See also GV_ITEM.
UINT GetItemState(int nRow, int nCol) const
Gets the state of the given cell.
See also GV_ITEM.
BOOL SetItemFormat(int nRow, int nCol, UINT nFormat)
Sets the format of the given cell. Returns TRUE on success. Default
implementation of cell drawing uses CDC::DrawText, so any of the DT_* formats are available.
See also GV_ITEM.
UINT GetItemFormat(int nRow, int nCol) const
Gets the format of the given cell (default returns a CDC::DrawText DT_* format).
See also GV_ITEM.
BOOL SetItemBkColour(int nRow, int nCol,
COLORREF cr = CLR_DEFAULT)
Sets the background colour of the given cell. Returns TRUE on success.
See also GV_ITEM.
COLORREF GetItemBkColour(int nRow, int nCol) const
Gets the background colour of the given cell.
See also GV_ITEM.
BOOL SetItemFgColour(int nRow, int nCol,
COLORREF cr = CLR_DEFAULT)
Sets the foreground colour of the given cell. Returns TRUE on success.
See also GV_ITEM.
COLORREF GetItemFgColour(int nRow, int nCol) const
Gets the foreground colour of the given cell.
See also GV_ITEM.
BOOL SetItemFont(int nRow, int nCol, LOGFONT* lf)
Sets the font of the given cell. Returns TRUE on success.
See also GV_ITEM.
LOGFONT* GetItemFont(int nRow, int nCol) const
Gets the font of the given cell.
See also GV_ITEM.
int InsertColumn(LPCTSTR strHeading,
UINT nFormat, int nColumn = -1)
Inserts a column at the position given by nCol, or at
the end of all columns if nCol is < 0. strHeading is the column heading
and nFormat the format. Returns the position of the inserted column.
int InsertRow(LPCTSTR strHeading, int nRow = -1)
Inserts a row at the position given by nRow, or at
the end of all rows if nRow is < 0. strHeading is the row heading.
The format of each cell in the row will be that of the cell in the first
row of the same column. Returns the position of the inserted row.
BOOL DeleteColumn(int nColumn)
Deletes column "nColumn", return TRUE on success.
BOOL DeleteRow(int nRow)
Deletes row "nRow", return TRUE on success.
BOOL DeleteAllItems()
Deletes all rows and contents in the grid.
BOOL DeleteNonFixedRows()
Deletes all non-fixed rows in the grid.
BOOL AutoSizeRow(int nRow)
Auto sizes the row to the size of the largest item.
BOOL AutoSizeColumn(int nCol)
Auto sizes the column to the size of the largest item.
void AutoSizeRows()
Auto sizes all rows.
void AutoSizeColumns()
Auto sizes all columns.
void AutoSize()
Auto sizes all rows and columns.
void ExpandColumnsToFit()
Expands the column widths to fit the grid area.
void ExpandRowsToFit()
Expands the row heights to fit the grid area.
void ExpandToFit()
Expands the rows and columns to fit the grid area.
Sets the range of selected cells.
See also CCellRange.
void SetSelectedRange(int nMinRow, int nMinCol,
int nMaxRow, int nMaxCol,
BOOL bForceRepaint = FALSE);
Sets the range of selected cells.
BOOL IsValid(int nRow, int nCol)
Returns TRUE if the given row and column is valid.
BOOL IsValid(const CCellID& cell)
Returns TRUE if the given cell is valid.
BOOL IsValid(const CCellRange& range)
Returns TRUE if the given cell range is valid.
CCellID GetNextItem(CCellID& cell, int nFlags) const
Searches for a cell that has the specified properties and that bears the
specified relationship to a given item. (See also CListCtrl::GetNextItem and
Cell Searching options)
BOOL SortTextItems(int nCol, BOOL bAscending)
Sorts the grid on the given column based on cell text.
Returns TRUE on success.
BOOL SortItems(PFNLVCOMPARE pfnCompare, int nCol,
BOOL bAscending, LPARAM data = 0)
Sorts the grid on the given column using the supplied
compare function pfnCompare. See CListCtrl::SortItems for information in the
form of this function. Returns TRUE on success.
GVIF_TEXT - Cell text will be accessed
GVIF_IMAGE - Cell image number will be accessed
GVIF_PARAM - Cell user data (lParam) will be accessed
GVIF_STATE - Cell state will be accessed
GVIF_BKCLR - Cell background colour will be accessed
GVIF_FGCLR - Cell foreground colour will be accessed
GVIF_FORMAT - Cell format field will be accessed
GVIF_FONT - Cell logical font will be accessed
GVIS_FOCUSED - Cell has focus
GVIS_SELECTED - Cell is selected
GVIS_DROPHILITED - Cell is drop highlighted
GVIS_READONLY - Cell is read-only and cannot be edited
GVIS_FIXED - Cell isfixed (not used)
GVIS_MODIFIED - Cell has been modified
GVNI_FOCUSED - Search for focus cell
GVNI_SELECTED - Search for selected cells
GVNI_DROPHILITED - Search for drop highlighted cells
GVNI_READONLY - Search for read-only cells
GVNI_FIXED - Search forfixed cells (not used)
GVNI_MODIFIED - Search for modified cells
GVNI_ABOVE - Search above initial cell
GVNI_BELOW - Search below initial cell
GVNI_TOLEFT - Search to the left of the initial cell
GVNI_TORIGHT - Search to the right of the initial cell
GVNI_ALL - Search all cells in the grid starting from the given cell
GVNI_AREA - Search all cells below and to the right of the given cell
virtualvoid OnEditCell(int nRow, int nCol, UINT nChar) - Starting edit
virtualvoid OnEndEditCell(int nRow, int nCol, CString str) - ending edit
virtualvoid CreateInPlaceEditControl(CRect& rect, DWORD dwStyle, int nRow, int nCol,
LPCTSTR szText, int nChar) - Create the inplace edit control
Drawing
virtual CSize GetCellExtent(int nRow, int nCol, CDC* pDC) - Returns Size of cell
according to cell
contents.
virtualvoid OnDraw(CDC& origDC); - Draws everything
virtual BOOL DrawFixedCell(CDC* pDC, int nRow, int nCol, - Draws Fixed cells
CRect rect, BOOL bEraseBk=FALSE)
virtual BOOL DrawCell(CDC* pDC, int nRow, int nCol, - Draws normal cells
CRect rect, BOOL bEraseBk=FALSE)
Construction and Cleanup
virtual CGridCell* CreateCell(int nRow, int nCol) - Creates a new cell and
initialises it.
virtualvoid EmptyCell(CGridCell* cell, int nRow, int nCol) - Performs any cleanup
necessary before removing
cells
This would not have been possible without the following authors
making their code freely available:
Joe Willcoxson: Joe's original code spurred this project on, and
provided the basic structure of this grid control.
Keith Rule: Keith provided a neat CMemDC
class to make flicker free display simple, and provided sample OLE copy/paste/drag/drop
code.
Ravi Reddy: I used a derivation of Ravi's listview
printing code.
Zafir Anjum: Provided the starting point for my CInPlaceEdit,
the sorting routines and the TitleTip code, and is the site maintainer for The MFC Programmers Sourcebook,
at www.codeguru.com. Zafir has done a great
job of allowing devlopers to swap code and learn from each other.
All those who contribute to the MFC Programmers Sourcebook:
Without you all I would not have been able to write this.
All those who sent in bug reports, suggestions, improvements and encouragement. Thank you!
Memory leak fix (Jens Bohlmann )
Mistype in CMemDC.h - Claus Arend-Schneider
Bug in GetSelectedCount - Lyn Newton
1.02 4 Mar 1998
Scrolling a little neater (less dead area)
Cell selection via OnTimer correctly updates Focus cell
1.03 31 Mar 1998
OnEditCopy, OnEditCut and OnEditPaste clipboard functions added.
Ctrl-X,Ctrl-C and Ctrl-V now initiate clipboard cut, copy and paste.
Support for OLE drag and drop.
Support for Microsoft intellimouse.
"DeleteContents" changed to "DeleteAllItems".
ExpandRowsToFit and ExpandColumnsToFit added.
Added SetHeaderSort and GetHeaderSort.
ExpandRowsToFit and ExpandColumnsToFit added.
Selected cell IDs now stored in a map instead of an array.
Scrolling and scroll selection tweaked a little.
Several minor bugs fixed.
LVN_ENDLABELEDIT now handled using ON_NOTIFY_REFLECT_EX so the parent can
handle it too.
GetItemText() now public.
1.04 5 April 1998
Added Ctrl-A = OnEditSelectAll.
Fixed CGridDropTarget double register problem
Minor bug in CopyTextFromGrid (assert on empty string) fixed.
Cleaned up reponse to m_bEditable (OnDrop and Ctrl-X disabled).
1.05 10 May 1998
Memory leak fixed. (Yuheng Zhao)
Changed OLE initialisation (Carlo Comino)
Added separate fore + background cell colours (John Crane).
ExpandToFit etc cleaned up - now decreases and increases cell sizes to
fit client area.
Added notification messages for the grid's parent
Added GVIS_READONLY state
1.06 20 May 1998
Added TAB key handling (Use Get/SetHandleTabKey to toggle). (Daniela Rybarova)
Intellimouse code correction for whole page scrolling (Paul Grant)
Fixed 16 bit thumb track problems (now 32 bit) (Paul Grant)
Fixed accelerator key problem in CInPlaceEdit (Matt Weagle)
Fixed Stupid ClassWizard code parsing problem (Michael A. Barnhart)
Double buffering now programmatically selectable (Use Get/SetDoubleBuffering)
Workaround for win95 drag and drop registration problem
Corrected UNICODE implementation of clipboard stuff
Dragging and dropping from a selection onto itself no no longer causes the
cells to be emptied
1.07 26 July 1998
Added EnsureVisible (Roelf Werkman)
Fixed delete key problem on read-only cells (Serge Weinstock)
OnEndInPlaceEdit sends notification AFTER storing the modified text in the cell.
Added CreateInPlaceEditControl to make it easier to change the way cells are edited. (suggested by Chris Clark)
Added Set/GetGridColor.
Tweaked CopyTextToClipboard a little.
SetModified called when cutting text or hitting DEL. (Jonathan Watters)
Focus cell made visible when editing begins.
Blank lines now treated correctly when pasting data
Removed ES_MULTILINE style from the default edit control
Added virtual CreateCell(row, col) function for cell creation and initialisation.
Fonts now specified on a per-cell basis using Get/SetItemFont
1.08 6 Aug 1998
Ctrl+arrows now allows cell navigation.
Modified CreateInPlaceEditControl to accept ID of control.
Added Titletips to grid cells. (Added EnableTitleTips / GetTitleTips)
1.09 12 Sep 1998
When printing, parent window title is printed in header - Gert Rijs
GetNextItem search with GVNI_DROPHILITED now returns cells with
GVIS_DROPHILITED set, instead of GVIS_FOCUSED (Franco Bez)
(Also fixed minor bug in GetNextItem) (Franco Bez)
Cell selection using Shift+arrows works - Franco Bez
SetModified called after edits ONLY if contents changed (Franco Bez)
Cell colours now dithered in 256 colour screens.
Support for MSVC 4.2 (Graham Cheetham)
1.10 29 Nov 1998
Titletips now disappear on a scroll event. Compiler errors
fixed. Grid lines drawing fixed (Graham Cheetham).
Cell focus fix on Isert Row/Col (Jochen Kauffmann)
Added DeleteNonFixedRows() (John Rackley)
Message #define conflict fixed (Oskar Wieland)
Titletips & cell insert/delete fix (Ramesh Dhar)
Titletips repeat-creation bug fixed.
GVN_SELCHANGED message now sends current cell ID
Font resource leak in GetTextExtent fixed (Gavin Jerman)
More TAB fixes (Andreas Ruh)
ID_EDIT_* handlers added.
1.11 2 Dec 1998
GetNextItem bug fix (suggested by Francis Fu)
InsertColumn (-1) fix (Roy Hopkins)
Was too liberal with the "IsEditable"'s. oops. (Michel Hete)
Made IsCellVisivle public, and added IsCellEditable.
1.11a 4 Jan 1999
Compiler errors in VC6 fixed.
1.12 10 Apr 1999
Cleanup to allow GRIDCONTROL_NO_CLIPBOARD define
CE #defines added. (Thanks to Frank Uzzolino for a start on this)
TitleTip display fixed for cells with images, plus it now uses cell font
Added GetTextRect and IsCellFixed
Focus change problem when resizing columns fixed (Sergey Nikiforenko)
Grid line drawing problem in fixed cells fixed (Sergey Nikiforenko)
CreateCell format persistance bug fixed (Sergey Nikiforenko)
DeleteColumn now returns TRUE (oops) (R. Elmer)
Enter, Tab and Esc key problem (finally) fixed - Darren Webb and Koay Kah Hoe
OnSize infinite loop fixed - Steve Kowald
GVN_SELCHANGING and GVN_SELCHANGED values changed to avoid conflicts (Hiroaki Watanabe)
Added single row selection mode (Yao Cai)
Mollified image drawing clip problem slightly (still not happy with it)
Reduced unnecessary redraws significantly
GetNextItem additions and bug fix, and GVNI_AREA search option (Franco Bez)
Added GVIS_MODIFIED style for cells, so individual cells can have their modification
status queried. (Franco Bez)
Last updated: April 10, 1999.
Tools:
Add www.codeguru.com to your favorites Add www.codeguru.com to your browser search box IE 7 | Firefox 2.0 | Firefox 1.5.xReceive news via our XML/RSS feed
RATE THIS ARTICLE:
Excellent Very Good Average Below Average Poor
(You must be signed in to rank an article. Not a member? Click here to register)