Skip to main content

How To Custom Paint the Grid Control Using Custom Painters

  • 3 minutes to read

If you need to custom paint grid View elements, the standard implementation is to handle associated events.

However, for some elements, the only way is to override methods of classes used to paint these elements. You will also need to override methods that return an appropriate painter class.

The ViewInfo and painter getters use a special naming convention. All methods that provide access to ViewInfo objects use the following identifier pattern: GetXXXViewInfoClass. Use the GetPainterClass method to access each instance of a painter class from the ViewInfo object.

To illustrate how you can implement custom paint tasks in these cases, consider the following example. Suppose you need to custom paint the master data row. The grid doesn’t have an associated event for this, so you’ll need to derive from the TcxGridMasterDataRowViewInfo and TcxGridMasterDataRowPainter classes.

In the TcxGridMasterDataRowViewInfo descendant, override the GetPainterClass method, within which you return the TcxGridMasterDataRowPainter‘s subclass.

Then, to inform the control that new classes are now used to display the master data row, implement descendants of the following classes and override the following methods:

And lastly, override the TcxMyGridMasterDataRowPainter.DrawExpandButtonCell method to paint the master data row’s expand button area with the specified color.

The following example demonstrates how to implement the master data row custom painting using the described inheritance mechanism:

// ...
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, cxStyles, cxCustomData, cxGraphics, cxFilter, cxData, cxDataStorage, cxEdit, DB, cxDBData, cxGridLevel, cxGridCustomTableView, cxGridTableView, cxGridDBTableView, cxClasses, cxControls, cxGridCustomView, cxGrid, DBTables, cxGridRows;
type
  TcxMyGridDBTableView = class(TcxGridDBTableView)
  protected
    function GetViewDataClass: TcxCustomGridViewDataClass; override;
  end;
  TcxMyGridViewData = class(TcxGridViewData)
  protected
    function GetRecordClass(ARecordInfo: TcxRowInfo): TcxCustomGridRecordClass; override;
  end;
  TcxMyGridMasterDataRow = class(TcxGridMasterDataRow)
  protected
    function GetViewInfoClass: TcxCustomGridRecordViewInfoClass; override;
  end;
  TcxMyGridMasterDataRowViewInfo = class(TcxGridMasterDataRowViewInfo)
  protected
    function GetPainterClass: TcxCustomGridCellPainterClass; override;
  end;
  TcxMyGridMasterDataRowPainter = class(TcxGridMasterDataRowPainter)
  protected
    procedure DrawExpandButtonCell; override;
  end;
  TForm1 = class(TForm)
    Table1: TTable;
    DataSource1: TDataSource;
    DataSource2: TDataSource;
    Table2: TTable;
    cxGrid1: TcxGrid;
    cxGrid1DBTableView1: TcxGridDBTableView;
    // ...
    cxGrid1Level1: TcxGridLevel;
    cxGrid1Level2: TcxGridLevel;
    cxGrid2Level1: TcxGridLevel;
    cxGrid2: TcxGrid;
    cxGrid2Level2: TcxGridLevel;
    cxGrid2DBTableView1: TcxGridDBTableView;
    cxGrid2TableView1: TcxGridTableView;
    procedure FormCreate(Sender: TObject);
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
uses
  cxGridDBDataDefinitions;
{ TcxMyGridDBTableView }
function TcxMyGridDBTableView.GetViewDataClass: TcxCustomGridViewDataClass;
begin
  Result := TcxMyGridViewData;
end;
{ TcxMyGridViewData }
function TcxMyGridViewData.GetRecordClass(
  ARecordInfo: TcxRowInfo): TcxCustomGridRecordClass;
begin
  if GridView.IsMaster then
    Result := TcxMyGridMasterDataRow
  else
    Result := inherited GetRecordClass(ARecordInfo);
end;
{ TcxMyGridMasterDataRow }
function TcxMyGridMasterDataRow.GetViewInfoClass: TcxCustomGridRecordViewInfoClass;
begin
  Result := TcxMyGridMasterDataRowViewInfo;
end;
{ TcxMyGridMasterDataRowViewInfo }
function TcxMyGridMasterDataRowViewInfo.GetPainterClass: TcxCustomGridCellPainterClass;
begin
  Result := TcxMyGridMasterDataRowPainter;
end;
{ TcxMyGridMasterDataRowPainter }
procedure TcxMyGridMasterDataRowPainter.DrawExpandButtonCell;
var
  ABounds: TRect;
begin
  Canvas.Brush.Color := $4FC8FB;
  ABounds := TcxMyGridMasterDataRowViewInfo(ViewInfo).ExpandButtonCellViewInfo.Bounds;
  Canvas.FillRect(ABounds);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
  AView: TcxMyGridDBTableView;
begin
  cxGrid2.BeginUpdate;
  try
    AView := TcxMyGridDBTableView(cxGrid2.CreateView(TcxMyGridDBTableView));
    AView.Assign(cxGrid1DBTableView1);
    cxGrid2Level1.GridView := AView;
    AView := TcxMyGridDBTableView(cxGrid2.CreateView(TcxMyGridDBTableView));
    AView.Assign(cxGrid1DBTableView2);
    cxGrid2Level2.GridView := AView;
  finally
    cxGrid2.EndUpdate;
  end;
end;
end.

Here is the code execution result:

See Also