Skip to main content
Table of Contents

Hints & comments

Two ways to attach extra text to a cell: a tooltip on hover, or a persistent comment with a corner indicator and a popup balloon.

Overview

Mechanism API When to use
Hint Grid.Hints[col, row] or OnGetCellHint Tooltip on hover. Doesn't show in the cell itself.
Comment Grid.Comments[col, row] Persistent annotation. Shows a small indicator in the corner; balloon opens on hover or click.

Comments stay visible when the user moves away; hints disappear as soon as the cursor leaves the cell.

Hints (tooltips)

Static hint per cell

Inline example 1PascalC++
Grid.Hints[1, 2] := 'This value was imported from the ERP system';
Grid->Hints[1][2] = L"This value was imported from the ERP system";

Dynamic hint via OnGetCellHint

For hints that depend on cell content:

Provide a dynamic hint per cellPascalC++
procedure TForm1.GridGetCellHint(Sender: TObject;
  ACell: TTMSFNCDataGridCellCoord; var AHint: string);
begin
  if ACell.Column = StatusColumn then
    AHint := 'Status: ' + Grid.Strings[ACell.Column, ACell.Row];
end;
void __fastcall TForm1::GridGetCellHint(TObject *Sender,
  const TTMSFNCDataGridCellCoord &ACell, System::UnicodeString &AHint)
{
  TTMSFNCDataGridCellCoord Cell = ACell;
  if (Cell.Column == StatusColumn)
    AHint = "Status: " + Grid->Strings[Cell.Column][Cell.Row];
}

When both the static Hints[] array and the event are set for the same cell, the event wins.

HTML in hints

The grid's HTML engine renders inside hints too:

Inline example 2PascalC++
Grid.Hints[1, 2] :=
  '<B>Imported value</B><BR>' +
  '<FONT color="gcGray" size="10">Source: ERP, 2025-01-12</FONT>';
Grid->Hints[1][2] =
  L"<B>Imported value</B><BR>" +
  L"<FONT color=\"gcGray\" size=\"10\">Source: ERP, 2025-01-12</FONT>";

See HTML, anchors & highlighting for the full tag reference.

Comments

DataGrid cells showing corner comment indicators DataGrid cells showing corner comment indicators

Set a comment programmatically

Inline example 3PascalC++
Grid.Comments[1, 3] := 'Reviewed by J. Smith on 2025-01-15';
Grid->Comments[1][3] = L"Reviewed by J. Smith on 2025-01-15";

A small indicator appears in the cell corner. Hovering the cell — or clicking the indicator — opens the comment balloon.

Set a comment via OnGetCellProperties

For dynamic comments that depend on cell content:

Set a comment dynamically per cellPascalC++
procedure TForm1.GridGetCellProperties(Sender: TObject;
  ACell: TTMSFNCDataGridCell);
begin
  if ACell.Column = ReviewColumn then
    ACell.Comment := 'Last reviewed: ' + DateToStr(Grid.Floats[ReviewColumn, ACell.Row]);
end;
void __fastcall TForm1::GridGetCellProperties(TObject *Sender,
  TTMSFNCDataGridCell *ACell)
{
  if (ACell->Column == ReviewColumn)
    ACell->Comment = "Last reviewed: " + DateToStr(Grid->Floats[ReviewColumn][ACell->Row]);
}

React to clicks on the indicator

Attach an anonymous method as the click handler:

React to comment indicator clicksPascalC++
type
  // OnCommentIndicatorClick is protected; a cracker class re-publishes it.
  TCellCracker = class(TTMSFNCDataGridCell)
  public
    property OnCommentIndicatorClick;
  end;

// OnCommentIndicatorClick is a plain TNotifyEvent whose Sender is the cell itself,
// so a method handler reads the cell from Sender.
procedure TForm1.GridGetCellProperties(Sender: TObject;
  ACell: TTMSFNCDataGridCell);
begin
  TCellCracker(ACell).OnCommentIndicatorClick := CommentIndicatorClick;
end;

procedure TForm1.CommentIndicatorClick(Sender: TObject);
var
  Cell: TTMSFNCDataGridCell;
begin
  Cell := Sender as TTMSFNCDataGridCell;
  ShowMessage('Comment: ' + Grid.Comments[Cell.Column, Cell.Row]);
end;
// OnCommentIndicatorClick is a plain TNotifyEvent whose Sender is the cell itself,
// so a method handler replaces the anonymous procedure and reads the cell from Sender.
// OnCommentIndicatorClick is protected; a cracker class re-publishes it.
class TCellCracker : public TTMSFNCDataGridCell
{
public:
  __property OnCommentIndicatorClick;
};

void __fastcall TForm1::GridGetCellProperties(TObject *Sender,
  TTMSFNCDataGridCell *ACell)
{
  static_cast<TCellCracker*>(ACell)->OnCommentIndicatorClick = CommentIndicatorClick;
}

void __fastcall TForm1::CommentIndicatorClick(TObject *Sender)
{
  TTMSFNCDataGridCell *Cell = dynamic_cast<TTMSFNCDataGridCell*>(Sender);
  ShowMessage("Comment: " + Grid->Comments[Cell->Column][Cell->Row]);
}

Customise the comment balloon

The balloon control is exposed via Grid.Root.CommentPopup (on the renderer). Use it to change appearance, padding, or behaviour:

Inline example 4PascalC++
Grid.Root.CommentPopup.FillColor   := gcLightYellow;
Grid.Root.CommentPopup.StrokeColor := gcGoldenrod;
Grid->Root->CommentPopup->FillColor   = gcLightYellow;
Grid->Root->CommentPopup->StrokeColor = gcGoldenrod;

Combining hints and comments

Hints and comments answer different questions: a hint is transient help while the pointer rests on a cell, a comment is a lasting annotation with a visible indicator. Many grids use both on the same column, for example a hint that explains the value and a comment that records who reviewed it. The example sets a static HTML hint and a static comment for individual cells, then wires OnGetCellHint for a dynamic hint and OnGetCellProperties for a dynamic comment on a whole column. Remember that the event wins over the static Hints[] value for the same cell, so use the static form only for cells the event does not cover.

HTML hints with dynamic hints and commentsPascalC++
procedure TForm1.SetupHintsAndComments;
begin
  // Static HTML hint and static comment for individual cells.
  Grid.Hints[1, 2] :=
    '<B>Imported value</B><BR>' +
    '<FONT color="gcGray" size="10">Source: ERP</FONT>';
  Grid.Comments[1, 3] := 'Reviewed by J. Smith';

  // Dynamic hint and comment for a whole column.
  Grid.OnGetCellHint := GridGetCellHint;
  Grid.OnGetCellProperties := GridGetCellProperties;
end;

procedure TForm1.GridGetCellHint(Sender: TObject;
  ACell: TTMSFNCDataGridCellCoord; var AHint: string);
begin
  // The event wins over the static Hints[] value for the same cell.
  if (ACell.Column = 2) and (ACell.Row > 0) then
    AHint := '<B>Status</B><BR>' + Grid.Strings[ACell.Column, ACell.Row];
end;

procedure TForm1.GridGetCellProperties(Sender: TObject;
  ACell: TTMSFNCDataGridCell);
begin
  if (ACell.Column = 2) and (ACell.Row > 0) then
    ACell.Comment := 'Row ' + IntToStr(ACell.Row) + ' was reviewed.';
end;
void __fastcall TForm1::SetupHintsAndComments()
{
  // Static HTML hint and static comment for individual cells.
  Grid->Hints[1][2] =
    "<B>Imported value</B><BR>"
    "<FONT color=\"gcGray\" size=\"10\">Source: ERP</FONT>";
  Grid->Comments[1][3] = "Reviewed by J. Smith";

  // Dynamic hint and comment for a whole column.
  Grid->OnGetCellHint = GridGetCellHint;
  Grid->OnGetCellProperties = GridGetCellProperties;
}

void __fastcall TForm1::GridGetCellHint(TObject *Sender,
  const TTMSFNCDataGridCellCoord &ACell, System::UnicodeString &AHint)
{
  TTMSFNCDataGridCellCoord Cell = ACell;
  // The event wins over the static Hints[] value for the same cell.
  if ((Cell.Column == 2) && (Cell.Row > 0))
    AHint = "<B>Status</B><BR>" + Grid->Strings[Cell.Column][Cell.Row];
}

void __fastcall TForm1::GridGetCellProperties(TObject *Sender,
  TTMSFNCDataGridCell *ACell)
{
  if ((ACell->Column == 2) && (ACell->Row > 0))
    ACell->Comment = "Row " + IntToStr(ACell->Row) + " was reviewed.";
}
  • Grid.Hints[col, row] — static hint text.
  • Grid.Comments[col, row] — static comment text.
  • OnGetCellHint — dynamic hint per cell.
  • OnGetCellProperties — set ACell.Comment and ACell.OnCommentIndicatorClick per cell.
  • Grid.CommentPopup — appearance of the comment balloon.

See also