The BrwsGrid Program
This section examines the BrwsGrid program you just ran. The grid in this program displays and allows you to edit the data stored in the data member m_data of the document.
In the following sections, code modules are followed by the explanations of the comments.
Initialization and Setting Column Count
 
void CBrwsGridView::OnInitialUpdate()
{
CGXBrowserView::OnInitialUpdate();
 
LockUpdate(TRUE);
GetParam()->EnableUndo(FALSE);
 
InitBrowserSettings(); //1
GetParam()->EnableTrackRowHeight();
SetColCount(
GetDocument()->m_data.GetColCount()); //2
SetStyleRange(CGXRange().SetCols(4),
CGXStyle().SetControl(GX_IDS_CTRL_CHECKBOX)); //3
SetStyleRange(CGXRange().SetCols(1),
CGXStyle().SetInterior(RGB(150,150,150)));
SetStyleRange(CGXRange().SetCols(2),
CGXStyle().SetTextColor(RGB(0,0,255)));
for(ROWCOL col = 1; col <=
GetDocument()->m_data.GetColCount(); col++) //4
 
{
SetValueRange(CGXRange(0, col),
GetDocument()->m_data.GetValueRowCol(0, col));
}
 
GetParam()->SetSortRowsOnDblClk(TRUE);
 
GetParam()->EnableUndo(TRUE);
LockUpdate(FALSE);
Redraw();
}
//1 Initializes the default browser settings.
//2 Set the column count in the grid based on the number of columns in your external data source. This allows you to set the base styles for the columns in the following lines.
//3 The following lines change the column base style in the corresponding columns, thereby affecting all the cells in those columns. Note that the browser grid does not allow you to set the styles for individual cells.
//4 Initialize the column names here.
Supplying the Row Count Dynamically
 
// Supply the record count to the grid.
long CBrwsGridView::OnGetRecordCount()
{
return GetDocument()->m_data.GetRowCount(); //1
}
//1 Supply the row count from your external data source here. This function will be called every time the grid has to be redrawn.
Managing Sorted Rows and Moved Columns
 
short CBrwsGridView::GetFieldFromCol(ROWCOL nCol)
{
return (short)
(GetColIndex(nCol) - GetHeaderCols()); //1
}
long CBrwsGridView::GetRecordFromRow(ROWCOL nRow)
{
return (long) GetRowIndex(nRow) -
(long) GetHeaderRows(); //2
}
//1 The browser grid enables moving columns by maintaining a map which translates the current moved column position into the original column before moving. This function converts the current column to the corresponding field in your data source. If your data source has columns that are zero-based, then you should make this function return the appropriate field number.
//2 The above discussion holds true for sorted rows as well.
Supplying the Value To the Grid and Storing the Changes
 
BOOL CBrwsGridView::OnLoadCellStyle(ROWCOL nRow, ROWCOL nCol, CGXStyle & style,
LPCTSTR pszExistingValue)
{
int nField = GetFieldFromCol(nCol); // 1
 
if (pszExistingValue == NULL && nRow >= GetFirstRow())// 2
{
if (!m_bNoValueNeeded && nField != -1 && nField <= (short)
GetDocument()->m_data.GetColCount()) // 3
{
style.SetValue(GetDocument()->m_data.GetValueRowCol(
GetRecordFromRow(nRow), nField));// 4
}
else
style.SetEnabled(FALSE);
}
return TRUE;
}
 
void CBrwsGridView::OnFlushCellValue(ROWCOL nRow, ROWCOL nCol,
LPCTSTR pszChangedValue) // 5
{
// cannot handle this.
if (pszChangedValue == NULL)
return;
 
int nField = GetFieldFromCol(nCol);
 
if (nField <= 0 || nField > (short)
GetDocument()->m_data.GetColCount()) // 6
{
SetWarningText(_T(
"You have tried to modify the value of an unbound field!"));
AfxThrowNotSupportedException();
return;
}
 
GetDocument()->m_data.StoreValueRowCol(GetRecordFromRow(nRow),
nField, pszChangedValue, gxOverride); //7
}
//1 Translate the column number to the field count in your data source.
//2 If pszExistingValue == NULL, then the grid already has the value in its internal buffer and you should only supply specific formatting here.
//3 If m_bNoValueNeeded == TRUE, then you do not have to supply the value here. This flag will be set while composing styles for tooltips which do not require the value.
//4 Get the value from your data source and set it in the composed style.
//5 This function will be called when the user edits one or more fields in a row and moved to another row and for each edited field in that row. Store the change back into your data source in this function.
//6 nField is greater than the field count if you had unbound columns in your grid. If that is the case, make sure that the unbound column is disabled. (This is usually the case.)
//7 Store the value back into your data source.
Deleting Rows
Override DeleteRows(), as shown in the tutorial sample code. The code is not discussed here line by line, since it is very elaborate. Please refer to the source code in the sample project for detailed information.
Basically, this code deals with the issue of deleting multiple non-contiguous rows. The problem is that as soon as you delete a row, the index of any row that is to be deleted (and that is below the current deleted row) becomes invalid.
It resolves the issue by deleting rows one at a time from bottom up, so that all the indexes for the rows to be deleted remain valid.
It also updates the internal data structure that is a map of the current moved rows to their original position before they were moved.