Blog
All Blog Posts | Next Post | Previous Post
Next Generation Data Grid for Delphi: Excel Style Selection
Today
Intro
When users see a grid, they almost instinctively expect Excel-like behavior:
click a cell, hold Shift, extend a range, use Ctrl+Shift+Arrow to jump to the edge of the data, and have the row and column headers highlight accordingly.
TTMSFNCDataGrid can do exactly that.
In this post, well configure the grid to:
-
behave like Excel in terms of selection (anchor vs active cell),
-
show familiar A, B, C column headers and 1, 2, 3 row headers,
-
visually highlight the selected row and column headers like Excel does.
All with a small amount of code, using a single TTMSFNCDataGrid that runs on VCL, FMX and TMS WEB Core.
What is Excel-style selection?
Excel-style selection in TTMSFNCDataGrid means:
-
the grid keeps track of an anchor cell (where the selection started),
-
the active end of the selection moves as you extend it,
-
keyboard shortcuts like Shift+Arrow and Ctrl+Shift+Arrow behave like Excel.
This mode is enabled simply by:
Grid.Options.Selection.RangeType := gsrtKeepFocusedCell;
RangeType is gsrtKeepFocusedCell, the grid keeps the focused cell on the anchor, while the selection range grows and shrinks from there, just like Microsoft Excel.Configuring the grid like a spreadsheet
Lets start with the basic setup to get a spreadsheet-sized grid and enable Excel-style selection.
procedure TForm2.FormCreate(Sender: TObject);
begin
TMSFNCDataGrid1.BeginUpdate;
TMSFNCDataGrid1.Clear;
// 1 fixed column for row numbers
TMSFNCDataGrid1.FixedColumnCount := 1;
// A large grid, Excel-style
TMSFNCDataGrid1.ColumnCount := 1000;
TMSFNCDataGrid1.RowCount := 100000;
// Narrow first column for row numbers
TMSFNCDataGrid1.ColumnWidths[0] := 35;
// Show selection in fixed row/column headers
TMSFNCDataGrid1.Options.Selection.ShowSelectionInFixedCells := True;
// Enable fixed cell selection like Excels header behavior
TMSFNCDataGrid1.Options.Mouse.FixedCellSelection := [
gfcsAll,
gfcsRow,
gfcsColumn,
gfcsRowRange,
gfcsColumnRange,
gfcsDisjunctRow,
gfcsDisjunctColumn
];
// Excel-style range selection
TMSFNCDataGrid1.Options.Selection.Mode := gsmCellRange;
TMSFNCDataGrid1.Options.Selection.RangeType := gsrtKeepFocusedCell;
// Smooth scrolling on touch devices
TMSFNCDataGrid1.Options.Mouse.TouchScrolling := True;
TMSFNCDataGrid1.EndUpdate;
end;
Key points:
-
gsmCellRangelets the user select rectangular ranges of cells. -
gsrtKeepFocusedCellenables Excel-style anchored selection. -
FixedColumnCount := 1reserves the first column for row numbers. -
ShowSelectionInFixedCells := Trueensures the fixed row/column headers reflect the current selection visually. -
FixedCellSelectionlets users click/drag on fixed cells (headers) to select rows, columns, or the full grid, again mimicking Excel
Creating Excel-like headers (AZ, AA, AB / 1, 2, 3 )
Next, we want the grid to look like a spreadsheet:
-
row headers:
1, 2, 3, ... -
column headers:
A, B, C, ..., Z, AA, AB, ...
We use a small helper to convert a zero-based column index to an Excel-style column name:
function SpreadSheetColName(const Col: Integer): string;
var
c: Char;
begin
Assert(Col >= 0);
if Col < 26 then
begin
c := 'A';
Inc(c, Col);
Result := c;
end
else
Result := SpreadSheetColName(Col div 26 - 1) +
SpreadSheetColName(Col mod 26);
end;
OnGetCellData:procedure TForm2.TMSFNCDataGrid1GetCellData(Sender: TObject;
ACell: TTMSFNCDataGridCellCoord; var AData: TTMSFNCDataGridCellValue);
begin
// First column: row numbers
if (ACell.Column = 0) and (ACell.Row > 0) then
AData := IntToStr(ACell.Row)
// First row: column letters
else if (ACell.Row = 0) and (ACell.Column > 0) then
AData := SpreadSheetColName(ACell.Column - 1);
end;
Centering header text
For a clean look, well center the text in the header row and fixed column.This is done through
OnGetCellLayout:procedure TForm2.TMSFNCDataGrid1GetCellLayout(Sender: TObject;
ACell: TTMSFNCDataGridCell);
begin
if (ACell.Column = 0) or (ACell.Row = 0) then
ACell.Layout.TextAlign := gtaCenter;
end;
Highlighting selected row and column headers
One of the subtle but important details in Excel is how it highlights row and column headers when a selection is active:
-
selecting a range highlights the corresponding row and column headers,
-
the top-left fixed cell is treated differently.
We can replicate this behavior using OnBeforeDrawCell combined with the grids built-in appearance settings:
procedure TForm2.TMSFNCDataGrid1BeforeDrawCell(Sender: TObject;
AGraphics: TTMSFNCGraphics; ACell: TTMSFNCDataGridCell;
var ACanDraw: Boolean);
var
r: TRectF;
begin
// 1) Custom highlight for selected fixed cells, excluding top-left (0,0)
if TMSFNCDataGrid1.IsFixedCellSelected(ACell.Coordinate)
and not ((ACell.Row = 0) and (ACell.Column = 0)) then
begin
r := ACell.Rect;
// Base fill from fixed layout, then darken it
AGraphics.Fill.Assign(TMSFNCDataGrid1.CellAppearance.FixedLayout.Fill);
AGraphics.Fill.Color := Darker(AGraphics.Fill.Color, 75);
AGraphics.Stroke.Assign(TMSFNCDataGrid1.CellAppearance.FixedLayout.Fill);
AGraphics.DrawRectangle(r, gcrmNone);
// Use focused layout for the selection indicator bar
AGraphics.Fill.Assign(TMSFNCDataGrid1.CellAppearance.FocusedLayout.Fill);
AGraphics.Stroke.Assign(
TMSFNCDataGrid1.CellAppearance.FocusedLayout.Stroke
);
// Top header row: draw a bar at the bottom
if ACell.Row = 0 then
AGraphics.DrawRectangle(
RectF(r.Left, r.Bottom - 3, r.Right, r.Bottom),
[gsBottom],
gcrmNone
)
// Left header column: draw a bar at the right
else
AGraphics.DrawRectangle(
RectF(r.Right - 3, r.Top, r.Right, r.Bottom),
[gsRight],
gcrmNone
);
// Prevent the default fill from drawing over our custom styling
ACell.DrawElements := ACell.DrawElements - [gcdFill];
end;
// 2) Cosmetic tweaks for header grid lines (Excel-like half-lines)
if (ACell.Row = 0) and (ACell.Column > 0) then
begin
// Remove default stroke and draw custom line in top header
ACell.DrawElements := ACell.DrawElements - [gcdStroke];
AGraphics.Stroke.Assign(TMSFNCDataGrid1.CellAppearance.FixedLayout.Stroke);
AGraphics.DrawLine(
PointF(ACell.Rect.Left, ACell.Rect.Bottom),
PointF(ACell.Rect.Left, ACell.Rect.Bottom - ACell.Rect.Height / 2)
);
end
else if (ACell.Column = 0) and (ACell.Row > 0) then
begin
// Same idea for left header column
ACell.DrawElements := ACell.DrawElements - [gcdStroke];
AGraphics.Stroke.Assign(TMSFNCDataGrid1.CellAppearance.FixedLayout.Stroke);
AGraphics.DrawLine(
PointF(ACell.Rect.Right, ACell.Rect.Top),
PointF(ACell.Rect.Right - ACell.Rect.Width / 2, ACell.Rect.Top)
);
end;
end;
What this does:
-
Uses
IsFixedCellSelectedto detect whether a header cell is part of the current selection. -
Draws a darkened background for the selected header cells using the grids fixed layout colors.
-
Adds a small indicator bar (bottom or right) in the focused layout color to visually link the header to the active selection.
-
Tweaks the header grid lines to better match Excels visual style.
Because we base our drawing on CellAppearance.FixedLayout and CellAppearance.FocusedLayout, any style changes you apply there (colors, themes, etc.) will automatically propagate to this custom drawing as well.
Conclusion
With a few configuration steps and lightweight customization, TTMSFNCDataGrid can closely mimic Excels look and selection behavior. Dynamic headers, anchored range selection, and subtle fixed-cell highlighting create an interface that feels instantly familiar to users. This provides a strong foundation for anything from simple data viewers to full spreadsheet-like toolswhile remaining fully cross-platform and easy to extend.
From here you can further extend the sample:
-
combine it with import/export to real Excel files using the FNC Grid Excel bridge.
-
add formatting, formulas, or cell controls,
-
or integrate with your existing business logic and datasets.
Pieter Scheldeman
Related Blog Posts
-
Next Generation Data Grid for Delphi: Getting Started
-
Next Generation Data Grid for Delphi: Adding, Formatting & Converting Data
-
Next Generation Data Grid for Delphi: Filtering & Sorting
-
Next Generation Data Grid for Delphi: Grouping
-
Next Generation Data Grid for Delphi: Webinar Replay Available!
-
Next Generation Data Grid for Delphi: Cell Controls
-
Next Generation Data Grid for Delphi: Master-Detail
-
Next Generation Data Grid for Delphi: Calculations
-
Next Generation Data Grid for Delphi: Import & Export
-
Next Generation Data Grid for Delphi: Template
-
Next Generation Data Grid for Delphi: Filter Row
-
Next Generation Data Grid for C++: Getting Started
-
Freebie Friday: Next Generation Grid Quick Sample Data
-
Next Generation Data Grid for Delphi: Columns Editor
-
Next Generation Data Grid for Delphi: File Drag & Drop
-
Next Generation Data Grid for Delphi: Visual Grouping
-
Next Generation Data Grid for Delphi: FMX Linux Support
-
Next Generation Data Grid for Delphi: Header & Footer Buttons
-
Next Generation Data Grid for Delphi: Paging
-
Next Generation Data Grid for Delphi: Cell Classes
-
Next Generation Data Grid for Delphi: Excel Style Selection
This blog post has not received any comments yet.
All Blog Posts | Next Post | Previous Post