When I fill a large grid with SetValueRange(), it is very slow. How should I fill the grid with cells?
a) If you call SetValueRange() for each cell, the grid will compute the cell, start the update mechanism (computing the window area, invalidate the cell, possibly send a hint to other views) and redraw the cell for each cell you called SetValueRange().
Therefore, it is recommended that you call LockUpdate(TRUE) before you do several SetValueRange() calls.
Example:
GetParam()->EnableUndo(FALSE);
BOOL bOldLock = LockUpdate(TRUE);
for (...)
SetValueRange(CGXRange(nRow, nCol), value);
LockUpdate(bOldLock);
Redraw();
b) A further optimization is to call StoreStyleRowCol instead of SetValueRange because SetValueRange has to check the read only state for each cell and also sends a StoreStyle notification to each cell type object before storing the value. But be aware that this will not create undo information, it will override read only cells and it will not notify the control object associated with a cell.
Example:
CGXStyle style;
for (...)
{
for (ROWCOL nCol = 1; nCol < 10; nCol++)
{
CString s;
s.Format("%d/%d", nRow/100, nCol);
style.SetValue("Hello");
StoreStyleRowCol(nRow, nCol, &style, gxOverride, 0);
}
}
c) If you are using the grid with the formula engine, the fastest way to fill the grid is to call SetNumberRowCol and SetTextRowCol directly. The speed improvements will be enormous compared to calling SetValueRange or SetExpressionRowCol for each cell. But again, be aware that cells are not checked if they are read-only, cell objects are not notified and no undo information will be created.
Example:
// Performace tests:
// Using SetNumberRowCol/SetTextRowCol directly
// instead of SetValueRange or SetExpressionRowCol
// will speed up the initialization of the grid
// enormously (just as fast as filling an array).
//
// Check it out below!
//
// NOTE: Directly calling these methods will bypass the
// notification of the associated cell type object for a
// cell (CGXControl::StoreStyle will not be called) and
// the readonly state of the cell will also not be
// checked.
//
DWORD ti = GetTickCount();
CGXFormulaSheet* pSheet = GetSheetContext();
CGXStyle style;
for (; nRow < 300; nRow++)
{
for (ROWCOL nCol = 1; nCol < 10; nCol++)
{
// CString s;
// s.Format("%d/%d", nRow/100, nCol);
// style.SetValue("Hello");
// StoreStyleRowCol(nRow, nCol, &style, gxOverride, 0);
pSheet->SetNumberRowCol(nRow, nCol, (double) nRow+nCol);
// pSheet->SetTextRowCol(nRow, nCol, _T("Hello"));
}
}
CString msg;
msg.Format("%d Ticks", GetTickCount()-ti);
AfxMessageBox(msg);
d) You may also take a look at the question "How do I implement a virtual grid? I want to supply cell contents on demand."
Often it is the most preferment way to use the grid virtual by overriding GetStyleRowCol and StoreStyleRowCol. When you intend to transfer many data to and from the grid, you might already maintain the data somewhere else, e.g. in a matrix or another data source (could also be a dbase file). In this case you should supply the on demand and not copy all the values to and from the grid.
If you have for example an array of strings, you may override GetStyleRowCol and supply the grid with the necessary data when it needs them. Whenever the grid changes cells data it calls StoreStyleRowCol, so that data can be stored back into your matrix.
See also the browsevw.cpp/.h sample in gridapp how to override GetStyleRowCol and StoreStyleRowCol. The customer area on our web site has some samples that demonstrate overriding GetStyleRowCol and StoreStyleRowCol. Search for "performance sample" in the Objective Grid customer area.