Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Steema/TeeGrid-VCL-FMX-Samples/llms.txt
Use this file to discover all available pages before exploring further.
TeeGrid uses TRowGroup objects to organize rows. Each grid has a root row group, and you can create sub-groups for hierarchical layouts.
Understanding TRowGroup
A TRowGroup is a band that contains:
- Columns - Column definitions
- Rows - Data rows
- Header - Column header band
- Headers - Additional header bands collection
- Footer - Footer bands collection
- Data - Associated data source
Each row group is self-contained with its own formatting and behavior.
Root Row Group
Access the main grid’s row group:
// The root group contains all primary grid data
var
RootGroup: TRowGroup;
begin
RootGroup := TeeGrid1.Grid.Root;
ShowMessage('Root has ' + IntToStr(RootGroup.Data.Count) + ' rows');
end;
Current Row Group
The focused/active row group:
// Get current focused group
var
CurrentGroup: TRowGroup;
begin
CurrentGroup := TeeGrid1.Grid.Current;
// Current might be root or a detail group
if CurrentGroup = TeeGrid1.Grid.Root then
ShowMessage('Root is focused')
else
ShowMessage('Detail group is focused');
end;
// Set current group
TeeGrid1.Grid.Current := SomeOtherGroup;
Row Group Properties
Each row group has independent properties:
procedure ConfigureGroup(Group: TRowGroup);
begin
// Columns
Group.Columns.Add('Name');
Group.Columns.Add('Value');
// Cell formatting
Group.Cells.Format.Font.Color := clBlack;
Group.Cells.Format.Font.Size := 10;
// Row formatting
Group.Rows.Height.Value := 25;
Group.Rows.Alternate.Visible := True;
Group.Rows.Alternate.Brush.Color := clLightGray;
// Header
Group.Header.Visible := True;
Group.Header.Format.Brush.Color := clNavy;
Group.Header.Format.Font.Color := clWhite;
// Selection
Group.Selected.Format.Brush.Color := clHighlight;
Group.Selected.Format.Font.Color := clWhite;
// Margins
Group.Margins.Left.Value := 5;
Group.Margins.Right.Value := 5;
// Read-only
Group.ReadOnly := False;
end;
Creating Sub-Groups
Sub-groups are created through master-detail expansion:
procedure TForm1.FormCreate(Sender: TObject);
begin
// Setup expander on root group
SetupExpander(TeeGrid1.Grid.Root);
// Event fired when detail group is created
TeeGrid1.Grid.Root.OnNewDetail := DetailGroupCreated;
end;
procedure TForm1.DetailGroupCreated(const Sender, NewGroup: TRowGroup);
begin
// NewGroup is the sub-group
ConfigureGroup(NewGroup);
// Can create another level of sub-groups
SetupExpander(NewGroup);
NewGroup.OnNewDetail := SubDetailCreated;
end;
Row Group Hierarchy
Navigate the group hierarchy:
var
Group: TRowGroup;
begin
Group := TeeGrid1.Grid.Current;
// Check if this is a detail group
if Group.IParent <> nil then
begin
// This is a sub-group, IParent is the parent group
ShowMessage('This is a detail group');
// Access parent group
Group := Group.IParent;
end;
// Check if this is the root
if Group = TeeGrid1.Grid.Root then
ShowMessage('This is the root group');
end;
Group-Specific Data
Each group has its own data source:
procedure TForm1.GetDetailData(const Sender: TExpanderRender;
const ARow: Integer; out AData: TObject);
var
DetailData: TArray<TOrderItem>;
begin
// Get detail data for this row
DetailData := GetOrderItems(ARow);
// Create data source for detail group
AData := TVirtualArrayData<TOrderItem>.Create(DetailData);
end;
procedure TForm1.DetailGroupCreated(const Sender, NewGroup: TRowGroup);
begin
// The detail group now has its own Data property
ShowMessage('Detail has ' + IntToStr(NewGroup.Data.Count) + ' rows');
end;
Group-Specific Columns
Detail groups can have different columns:
procedure TForm1.DetailGroupCreated(const Sender, NewGroup: TRowGroup);
begin
// Detail group inherits columns from its data
// But you can customize them
if NewGroup.Columns.Count > 0 then
begin
NewGroup.Columns[0].Width.Value := 100;
NewGroup.Columns[0].Header.Text := 'Order Item';
end;
// Or add calculated columns
var CalcCol := NewGroup.Columns.Add('Total');
CalcCol.ReadOnly := True;
end;
Group Selection
Each group has independent selection:
procedure TForm1.DetailGroupCreated(const Sender, NewGroup: TRowGroup);
begin
// Selection in detail group
NewGroup.Selected.Format.Brush.Color := clYellow;
NewGroup.Selected.Format.Brush.Visible := True;
// Handle selection changes
NewGroup.OnChangedSelected := DetailSelectionChanged;
end;
procedure TForm1.DetailSelectionChanged(Sender: TObject);
var
Group: TRowGroup;
begin
Group := TRowGroup(Sender);
// Get selected row in this group
if Group.Selected.Row >= 0 then
ShowMessage('Selected row ' + IntToStr(Group.Selected.Row) +
' in detail group');
end;
Each group has independent scrolling:
procedure ConfigureScrolling(Group: TRowGroup);
begin
// Scrolling mode
Group.Scrolling.Mode := TScrollingMode.Both; // Touch and mouse
// Scroll direction
Group.Scrolling.Horizontal := TScrollDirection.Normal;
Group.Scrolling.Vertical := TScrollDirection.Normal;
// Programmatic scrolling
Group.Scroll(0, 100); // Scroll 100 pixels down
end;
Group Painting
Customize group appearance:
procedure TForm1.DetailGroupCreated(const Sender, NewGroup: TRowGroup);
begin
// Background
NewGroup.Format.Brush.Color := TAlphaColors.Beige;
NewGroup.Format.Brush.Visible := True;
// Border
NewGroup.Format.Stroke.Color := TAlphaColors.Gray;
NewGroup.Format.Stroke.Width := 2;
NewGroup.Format.Stroke.Visible := True;
end;
Multiple Independent Grids
You can have multiple grids, each with its own root group:
procedure TForm1.FormCreate(Sender: TObject);
begin
// Grid 1 - Customers
TeeGrid1.Data := CustomersData;
TeeGrid1.Grid.Root.Cells.Format.Font.Color := clBlue;
// Grid 2 - Products
TeeGrid2.Data := ProductsData;
TeeGrid2.Grid.Root.Cells.Format.Font.Color := clGreen;
// Each grid has independent root groups
end;
Accessing All Groups
Iterate through all row groups:
procedure TForm1.IterateGroups(Group: TRowGroup; Level: Integer);
var
I: Integer;
ChildBand: TGridBand;
ChildGroup: TRowGroup;
begin
ShowMessage('Group at level ' + IntToStr(Level) +
' has ' + IntToStr(Group.Data.Count) + ' rows');
// Iterate children (expanded detail grids)
for I := 0 to Group.Rows.Children.Count - 1 do
begin
ChildBand := Group.Rows.Children.Row[I];
if ChildBand is TRowGroup then
begin
ChildGroup := TRowGroup(ChildBand);
IterateGroups(ChildGroup, Level + 1); // Recurse
end;
end;
end;
// Start from root
IterateGroups(TeeGrid1.Grid.Root, 0);
Different context menus for different groups:
procedure TForm1.TeeGrid1ContextPopup(Sender: TObject; MousePos: TPoint;
var Handled: Boolean);
var
Group: TRowGroup;
begin
Group := TeeGrid1.Grid.Current;
if Group = TeeGrid1.Grid.Root then
PopupMenu1.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y) // Master menu
else
PopupMenu2.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y); // Detail menu
Handled := True;
end;
Programmatic Group Creation
Manually create row groups (advanced):
var
NewGroup: TRowGroup;
MyData: TVirtualData;
begin
// Create data
MyData := TVirtualArrayData<TMyRecord>.Create(MyArray);
// Create group
NewGroup := TRowGroup.Create(nil, MyData);
NewGroup.OwnsData := True; // Group will free data
// Configure group
ConfigureGroup(NewGroup);
// Add as child of parent row
// (This is normally done automatically by expander)
end;
Group Events
OnChangedSelected
Fired when selection changes in the group:
Group.OnChangedSelected := GroupSelectionChanged;
procedure TForm1.GroupSelectionChanged(Sender: TObject);
var
Group: TRowGroup;
begin
Group := TRowGroup(Sender);
// Handle selection change
end;
OnNewDetail
Fired when a detail sub-group is created:
Group.OnNewDetail := DetailCreated;
procedure TForm1.DetailCreated(const Sender, NewGroup: TRowGroup);
begin
// Configure new detail group
end;
Focused Groups
Determine which group has focus:
var
Group: TRowGroup;
begin
Group := TeeGrid1.Grid.Current;
if Group.IsFocused then
ShowMessage('This group has focus');
// Move focus to another group
AnotherGroup.IsFocused := True;
TeeGrid1.Grid.Current := AnotherGroup;
end;
Best Practices
- Use
OnNewDetail to configure detail groups when they’re created
- Store references to important groups in form fields if needed
- Use
Current to determine which group has focus
- Apply consistent formatting within group levels
- Each group can have completely different columns and data
- Remember that selection, scrolling, and formatting are per-group
- Use distinct colors for different hierarchy levels
- Clean up expanded groups when not needed to save memory
- Use
OwnsData := True so groups manage their data lifecycle