Table of Contents

Cell controls

Embed live FMX/VCL controls inside grid cells — buttons, progress bars, checkboxes, radio buttons, bitmaps, even nested grids — and lay them out inside the cell with align or position rules.

Overview

Four flavours of in-cell content:

Type API Use it for
Live control Grid.Controls[col, row] := SomeControl Any FMX/VCL control: a button, a slider, a custom panel.
Built-in data control Grid.AddDataCheckBoxColumn(col), AddDataProgressBarColumn(col), AddRadioButtonColumn(col) Common controls that bind directly to the cell value.
Decorative elements Grid.AddButton(col, row), AddBitmap(col, row), AddCheckBox(col, row) Non-data controls for decoration or user actions.
Nested grid Grid.AddGrid(col, row) A full sub-grid living inside one cell (master-detail in one component).

For each live control you choose alignment (fills a cell edge — top, left, client, …) or position (anchored to a corner — top-left, center-right, …).

Cell controls Cell controls (dark theme)

Quick example

procedure TForm1.FormCreate(Sender: TObject);
var
  b: TButton;
  i: Integer;
begin
  Grid.BeginUpdate;
  try
    Grid.ColumnCount := 8;
    Grid.LinearFill;

    // Embed live FMX buttons in selected cells.
    b := TButton.Create(Self);
    b.Text := 'Client';
    Grid.Controls[4, 1] := b;
    Grid.ControlAligns[4, 1] := gcaClient;        // fills the cell

    b := TButton.Create(Self);
    b.Text := 'Top Right';
    Grid.Controls[2, 2] := b;
    Grid.ControlPositions[2, 2] := gcpTopRight;    // anchored at top-right

    // Built-in progress bar bound to the cell value.
    Grid.AddDataProgressBar(0, 5);
    Grid.Ints[0, 5] := 25;

    // Whole-column data-bound checkbox / radio button columns.
    Grid.AddDataCheckBoxColumn(5);
    Grid.AddRadioButtonColumn(6);
    for i := 0 to Grid.RowCount - 1 do
      Grid.Booleans[5, i] := Random(2) = 0;
  finally
    Grid.EndUpdate;
  end;
end;

Step by step

Live FMX/VCL controls

Assign any control instance to Grid.Controls[col, row]. The grid manages layout but not ownership — your form still owns the control instance.

b := TButton.Create(Self);
b.Text := 'Click me';
Grid.Controls[2, 3] := b;

Grid.ControlAligns[2, 3]    := gcaClient;        // fill cell
Grid.ControlPositions[2, 3] := gcpCenterCenter;  // or anchored to center
with Grid.ControlMargins[2, 3] do begin Left := 4; Top := 4; Right := 4; Bottom := 4; end;

ControlAligns (gcaTop, gcaLeft, gcaClient, …) and ControlPositions (gcpTopLeft, gcpCenterCenter, …) are mutually exclusive — set one, leave the other at its default.

Data-bound controls (whole column)

These render a live control bound to each cell's value:

Grid.AddDataCheckBoxColumn(5);         // column 5 → data-bound checkbox
Grid.AddDataProgressBarColumn(7);      // column 7 → data-bound progress bar

For data-bound checkboxes, Grid.Booleans[col, row] reads/writes the state. For progress bars, Grid.Ints[col, row] is the percentage (0–100).

Radio buttons are not data-bound. AddRadioButtonColumn renders a static radio button whose state you manage manually with Grid.SetRadioButton.

Grid.AddRadioButtonColumn(6);          // column 6 → static radio button

Buttons, bitmaps, and static checkboxes

These are decorative controls not directly tied to a cell value:

Grid.AddButton(2, 3, 'Open');          // button in cell (2, 3)
Grid.AddButtonColumn(2, 'Edit');       // button in every cell of column 2
Grid.AddBitmap(3, 3, MyBitmap);        // bitmap in cell (3, 3)
Grid.AddCheckBox(4, 5, False);         // static checkbox in cell (4, 5)
Combo box cell control Combo box cell control (dark theme)

Nested grid (sub-grid in a cell)

procedure TForm1.AddNestedGrid;
var
  g: TTMSFNCDataGridRenderer;
begin
  g := Grid.AddGrid(2, 9);              // returns a TTMSFNCDataGridRenderer
  g.ColumnCount := 5;
  g.LoadSampleData;
end;

The nested grid is a fully functional grid — you can nest grids inside cells of nested grids when your design calls for it.

Buttons that fire grid events

For buttons, handle clicks centrally via Grid.OnCellButtonClick rather than setting individual OnClick handlers — it keeps all button logic in one place:

procedure TForm1.GridCellButtonClick(Sender: TObject;
  AColumn, ARow: Integer);
begin
  case AColumn of
    EditColumn:  EditRecord(ARow);
    DeleteColumn: DeleteRecord(ARow);
  end;
end;

Bitmap cache for non-interactive controls

For performance, non-interactive cell controls can be rendered into a bitmap cache instead of kept as live framework controls in every visible cell. A live control is used only when the cell needs real interaction, such as focus or editing.

The default cache key includes the control type, dimensions, text/caption, focus state, and tag. If a custom control has additional visual state, add those property names with OnGetCellControlExtraProperties:

procedure TForm1.GridGetCellControlExtraProperties(Sender: TObject;
  AColumn, ARow: Integer; AControl: TControl;
  var AExtraProperties: TArray<string>);
begin
  if AControl is TPriorityBar then
    AExtraProperties := ['Level'];
end;

Use OnGetCellSupportsRealControl when a cell must host a live control instead of a cached bitmap:

procedure TForm1.GridGetCellSupportsRealControl(Sender: TObject;
  AColumn, ARow: Integer; AControl: TControl;
  var ASupportsRealControl: Boolean);
begin
  if AColumn = InteractiveColumn then
    ASupportsRealControl := True;
end;

Combining multiple control types with bitmap caching

This example adds a progress bar to one column, a button to another, and a checkbox column — then turns on bitmap caching for the progress bar so the grid stays performant with many rows:

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Progress bar column (non-interactive — use bitmap cache)
  Grid.AddDataProgressBarColumn(ProgressColumn);
  Grid.ControlAligns[ProgressColumn, -1] := gcaClient; // -1 applies to whole column

  // Button column (interactive — must stay a real control)
  Grid.AddButtonColumn(ActionColumn);
  Grid.Columns[ActionColumn].ControlWidth  := 80;
  Grid.Columns[ActionColumn].ControlHeight := 22;
  Grid.OnCellButtonClick := GridCellButtonClick;

  // Checkbox column (data-bound)
  Grid.AddDataCheckBoxColumn(DoneColumn);
  Grid.OnCellCheckBoxChange := GridCellCheckBoxChange;

  // Bitmap cache: progress bar doesn't need interaction — cache it
  // Real control required only for the action button column
  Grid.OnGetCellSupportsRealControl := GridGetCellSupportsRealControl;
end;

procedure TForm1.GridGetCellSupportsRealControl(Sender: TObject;
  AColumn, ARow: Integer; AControl: TControl;
  var ASupportsRealControl: Boolean);
begin
  ASupportsRealControl := (AColumn = ActionColumn);
end;
  • Grid.Controls[AColumn, ARow]
  • Grid.ControlAligns[AColumn, ARow]gcaNone, gcaTop, gcaLeft, gcaRight, gcaBottom, gcaClient
  • Grid.ControlPositions[AColumn, ARow] — nine corner constants (gcpTopLeftgcpBottomRight)
  • Grid.ControlMargins[AColumn, ARow] — per-cell margins (TTMSFNCMargins)
  • Grid.Columns[AColumn].ControlWidth / ControlHeight — per-column control dimensions
  • Grid.AddButton / AddButtonColumn — button in cell or column
  • Grid.AddBitmap / AddBitmapColumn — bitmap in cell or column
  • Grid.AddCheckBox / AddCheckBoxColumn — static checkbox
  • Grid.AddDataCheckBox / AddDataCheckBoxColumn — data-bound checkbox
  • Grid.AddDataProgressBar / AddDataProgressBarColumn — data-bound progress bar
  • Grid.AddRadioButtonColumn — radio button column
  • Grid.AddGrid(AColumn, ARow) — nested sub-grid
  • OnCellButtonClick, OnCellCheckBoxChange, OnCellRadioButtonChange

See also

  • Editing cells — inplace editors are a different mechanism (replace cell content during edit).
  • Custom cells — for owner-drawn rendering instead of embedded controls.
  • Merging cells — merged cells are often used to host one large control.
  • Demo: Demo/FMX/DataGrid/Basic/Cell Controls
  • Demo: Demo/FMX/DataGrid/Advanced/Grid in Grid