Skip to main content

How to Customize All Cell Objects at Once

  • 6 minutes to read

The Spreadsheet and Report Designer controls store cell data and cell custom styles in cell objects, usually accessible via the Table View worksheet’s Cells property and the CreateCell function.

Call the CreateCell function to access a specific cell object without any additional checks. If you are using the Cells property to access a specific cell object by its row and column indexes within a worksheet, check whether the cell object exists and create it if necessary:

var
  ATableView: TdxSpreadSheetTableView;
  ACell: TdxSpreadSheetCell;  // A variable for working with a cell object
//...
  ATableView := dxSpreadSheet1.ActiveSheetAsTable;
  if(ATableView.Cells[0, 0] <> nil) then  // If the cell object exists...
    ACell := ATableView.Cells[0, 0]  // Assigns it to the ACell variable
  else  // If there is no cell object at the specified position...
    ACell := ATableView.CreateCell(0, 0);  // Creates a new cell object at the position

While using the CreateCell function is more convenient, the Cells property is useful if you need to work only with initialized/modified worksheet cells without creating additional cell objects. For instance, if you need to apply specific style parameters to all initialized cells within the modified worksheet area, refer to the following code example:

var
  ATableView: TdxSpreadSheetTableView;
  ACell: TdxSpreadSheetCell;
  I, J: Integer;  // Cycle counters
//...
  ATableView := dxSpreadSheet1.ActiveSheetAsTable;
  ATableView.BeginUpdate;
  for I := 0 to ATableView.Dimensions.Bottom do  // Cycles through the all modified rows within the active worksheet
    begin
      for J := 0 to ATableView.Dimensions.Right do  // Cycles through the all modified columns within the active worksheet
        begin
          if(ATableView.Cells[I, J] <> nil) then  // If the cell object is actually exists...
            begin
              // Applies the custom background style to the cell
              ACell := ATableView.Cells[I, J];
              ACell.Style.Brush.BackgroundColor := clHighlight;
              ACell.Style.Brush.ForegroundColor := clMoneyGreen;
              ACell.Style.Brush.Style = sscfsThinRevDiagonalStrip;
            end;
        end;
    end;
  ATableView.EndUpdate;

As a result, the new background style is applied to all initialized cells in the active worksheet:

However, the ExpressSpreadSheet Suite provides a more convenient way to apply the same set of changes to all initialized cells in a worksheet. To use it, invoke either the Table View worksheet’s ForEachCell procedure or the EnumCells procedure of a particular row object, depending on the situation.

The EnumCells and ForEachCell procedures accept an anonymous procedure referring to the cell objects created in a row or worksheet, respectively. In the case of Delphi code, you can simplify the example above by including the cell background customization code within the anonymous procedure implementation:

var
  ATableView: TdxSpreadSheetTableView;
  ACell: TdxSpreadSheetCell;
//...
  ATableView := dxSpreadSheet1.ActiveSheetAsTable;
  ATableView.ForEachCell(
    procedure(ACell: TdxSpreadSheetCell)
    begin
// The ACell parameter addresses each valid cell object within the Table View worksheet
      ACell.Style.Brush.BackgroundColor = clHighlight;
      ACell.Style.Brush.ForegroundColor = clMoneyGreen;
      ACell.Style.Brush.Style = sscfsThinRevDiagonalStrip;
    end);

Since C++Builder does not support anonymous functions, you need to wrap the following TdxSpreadSheetTableViewForEachCellProc method interface exposed as the Invoke method:

__interface TdxSpreadSheetTableViewForEachCellProc;
typedef System::DelphiInterface<TdxSpreadSheetTableViewForEachCellProc> _di_TdxSpreadSheetTableViewForEachCellProc;
__interface TdxSpreadSheetTableViewForEachCellProc: public System::Interface
{
public:
  virtual void __fastcall Invoke(TdxSpreadSheetCell* ACell) = 0;
};

The following C++ code shows a template example that you can use to pass C++ methods as method references to Delphi. Place both the template class and the dummy enumeration type declaration to the project header file:

enum __DummyType {};  // The parameter type used as default
template<
  typename InvokeInterface,  // Interface with the virtual Invoke method
  typename TFunction,  // The function type
  typename TReturned,  // The returned data type
  typename TParameter1 = __DummyType>  // The returned parameter type
  class TMethodReference: public TInterfacedObject, public InvokeInterface
  {
    private:
    TFunction callback;
    public:
    TMethodReference(TFunction _callback): callback(_callback) {}
    HRESULT STDMETHODCALLTYPE QueryInterface(const GUID& riid, void** ppvObject)
    {
      return TinterfacedObject::QueryInterface(riid, ppvObject);
    }
    ULONG STDMETHODCALLTYPE AddRef(void)
    {
      return TinterfacedObject::_AddRef();
    }
    ULONG STDMETHODCALLTYPE Release(void)
    {
      return TinterfacedObject::_Release();
    }
    TReturned __fastcall Invoke(TParameter1 p1)
    {
      return callback(p1);
    }
  };

Then, implement the method used as an anonymous procedure, which contains all instructions applied to all initialized cells in a worksheet. The ACell parameter is used as a pointer to all valid cell objects within the Table View worksheet’s Dimensions area:

void CustomizeEachValidCell(TdxSpreadSheetCell* ACell)
{
  ACell->Style->Brush->BackgroundColor = clHighlight;
  ACell->Style->Brush->ForegroundColor = clMoneyGreen;
  ACell->Style->Brush->Style = sscfsThinRevDiagonalStrip;
}

Finally, invoke the CustomizeEachValidCell method:

TdxSpreadSheetTableView* ATableView;
//...
  ATableView = dxSpreadSheet1->ActiveSheetAsTable;
// Creates a new instance of the created TMethodReference template class
  _di_TdxSpreadSheetTableViewForEachCellProc proc = new
  TdxMethodReference<TdxSpreadSheetTableViewForEachCellProc,  // The referenced procedure type
  void (*)(  // The returned value type
    TdxSpreadSheetCell*),  // The argument type (the pointer to a cell object)
  void,  // The data type returned by the method
  TdxSpreadSheetCell*  // Pointer to the addressed cell objects
  >(CustomizeEachValidCell);  // The referenced method's name
// Invokes the ForEachCell method:
  ATableView->ForEachCell(proc);

The second overloaded TdxSpreadSheetTableView.ForEachCell procedure variant allows you to limit the area to which the anonymous procedure’s instructions are applied:

var
  ATableView: TdxSpreadSheetTableView;
  AArea: TRect;
//...
  ATableView := dxSpreadSheet1.ActiveSheetAsTable;
// Limits the processed cell objects with the selection area
  AArea := ATableView.Selection.Area;
  ATableView.ForEachCell(AArea,
    procedure(ACell: TdxSpreadSheetCell)
    begin
      ACell.Style.Brush.BackgroundColor := clHighlight;
      ACell.Style.Brush.ForegroundColor := clMoneyGreen;
      ACell.Style.Brush.Style := sscfsThinRevDiagonalStrip;
    end);

The row object’s EnumCells procedure applies only to cell objects within that row. In all other aspects, it works similarly to the ForEachCell procedure discussed earlier. Note that you need to check whether the row object actually exists within the worksheet:

var
  ATableView: TdxSpreadSheetTableView;
  ARowNumber: Integer;
//...
  ATableView := dxSpreadSheet1.ActiveSheetAsTable;
// Use the focused cell's row index to specify the row
  ARowNumber := ATableView.Selection.Area.Top;
// If the selected row excutally exits...
  if(ATableView.Rows[ARowNumber] <> nil) then
    begin
      ATableView.Rows[ARowNumber].EnumCells(
        procedure(ACell: TdxSpreadSheetCell)
        begin
          ACell.Style.Brush.BackgroundColor := clHighlight;
          ACell.Style.Brush.ForegroundColor := clMoneyGreen;
          ACell.Style.Brush.Style := sscfsThinRevDiagonalStrip;
        end);
    end;