Skip to main content
Table of Contents

Scrolling & scroll bars

Pixel-smooth or cell-snapping, continuous or release-only redraws, programmatic scroll-to, custom-styled or external scroll bars.

Overview

Scrolling is configured through three top-level grid properties — ScrollMode, ScrollUpdate, and CustomScrollBars — plus a handful of API methods for programmatic control. The defaults match Excel: smooth pixel scrolling with continuous redraw and OS-native scroll bars.

Scroll mode

Scroll modePascalC++
uses
  FMX.TMSFNCDataGrid;

procedure TForm1.SetScrollMode;
begin
  Grid.ScrollMode := gsmCellScrolling;
end;
void __fastcall TForm1::SetScrollMode()
{
  Grid->ScrollMode = gsmCellScrolling;
}
Value Effect
gsmPixelScrolling Smooth pixel-by-pixel scrolling (default).
gsmCellScrolling Snaps so the top-left visible cell is always fully aligned.

Pick gsmCellScrolling when fractional row/column visibility looks odd — for example a grid that imitates a paper form.

Scroll update strategy

Scroll update strategyPascalC++
uses
  FMX.TMSFNCDataGrid;

procedure TForm1.SetScrollUpdate;
begin
  Grid.ScrollUpdate := gsuOnce;
end;
void __fastcall TForm1::SetScrollUpdate()
{
  Grid->ScrollUpdate = gsuOnce;
}
Value Effect
gsuContinuous Redraws while the user drags the scroll thumb (default).
gsuOnce Redraws only when the thumb is released.

Use gsuOnce on very large grids where continuous repaint costs become noticeable.

Programmatic scrolling

Programmatic scrollingPascalC++
uses
  FMX.TMSFNCDataGrid;

procedure TForm1.ScrollProgrammatically;
begin
  Grid.Scroll(0, 500);            // pixel offset (h, v)
  Grid.GoToCell(MakeCell(3, 20)); // navigate to a specific cell
end;

procedure TForm1.ReadScrollPosition;
var
  H, V: Single;
begin
  H := Grid.GetHScrollValue;
  V := Grid.GetVScrollValue;
end;

procedure TForm1.RebuildKeepingScroll;
begin
  Grid.Root.SaveScrollPosition;
  Grid.LoadFromCSVData('data.csv');
  Grid.Root.RestoreScrollPosition;
end;
void __fastcall TForm1::ScrollProgrammatically()
{
  Grid->Scroll(0, 500);            // pixel offset (h, v)
  Grid->GoToCell(Fmx::Tmsfncdatagridcore::MakeCell(3, 20)); // navigate to a specific cell
}

void __fastcall TForm1::ReadScrollPosition()
{
  float H = Grid->GetHScrollValue();
  float V = Grid->GetVScrollValue();
}

void __fastcall TForm1::RebuildKeepingScroll()
{
  Grid->Root->SaveScrollPosition();
  Grid->LoadFromCSVData("data.csv");
  Grid->Root->RestoreScrollPosition();
}

Scroll events

Scroll eventsPascalC++
uses
  System.SysUtils, FMX.TMSFNCDataGrid;

procedure TForm1.GridHScroll(Sender: TObject; APosition: Single);
begin
  Caption := Format('H-scroll: %.0f', [APosition]);
end;

procedure TForm1.GridVScroll(Sender: TObject; APosition: Single);
begin
  Caption := Format('V-scroll: %.0f', [APosition]);
end;
void __fastcall TForm1::GridHScroll(TObject *Sender, float APosition)
{
  Caption = Format("H-scroll: %.0f", ARRAYOFCONST(((long double)APosition)));
}

void __fastcall TForm1::GridVScroll(TObject *Sender, float APosition)
{
  Caption = Format("V-scroll: %.0f", ARRAYOFCONST(((long double)APosition)));
}

Assign via OnHScroll and OnVScroll.

Custom scroll bars

Replace the OS scroll bars with the grid's own styled scroll bars (TTMSFNCScrollBar) for a consistent look across platforms:

Custom scroll barsPascalC++
uses
  FMX.TMSFNCScrollBar, FMX.TMSFNCDataGrid;

procedure TForm1.ConfigureCustomScrollBars;
var
  HSB, VSB: TTMSFNCScrollBar;
begin
  Grid.CustomScrollBars := True;

  // Access them directly
  HSB := Grid.CustomHorizontalScrollBar;
  VSB := Grid.CustomVerticalScrollBar;

  // Fill the full edge (touch the corners) instead of leaving a gap
  Grid.StretchScrollBars := True;

  // Hide a scroll bar without disabling scroll
  Grid.HorizontalScrollBarVisible := False;
  Grid.VerticalScrollBarVisible   := True;
end;
void __fastcall TForm1::ConfigureCustomScrollBars()
{
  Grid->CustomScrollBars = true;

  // Access them directly
  TTMSFNCScrollBar *HSB = Grid->CustomHorizontalScrollBar;
  TTMSFNCScrollBar *VSB = Grid->CustomVerticalScrollBar;

  // Fill the full edge (touch the corners) instead of leaving a gap
  Grid->StretchScrollBars = true;

  // Hide a scroll bar without disabling scroll
  Grid->HorizontalScrollBarVisible = false;
  Grid->VerticalScrollBarVisible   = true;
}

External scroll bars

For layouts where the scroll bars need to live outside the grid control (e.g. in a separate panel), implement ITMSFNCDataGridExternalScrollBar on any control and assign it:

External scroll barsPascalC++
uses
  FMX.TMSFNCDataGrid;

// MyVerticalScrollBarAdapter / MyHorizontalScrollBarAdapter are controls that
// implement ITMSFNCDataGridExternalScrollBar.
procedure TForm1.AssignExternalScrollBars;
begin
  Grid.ExternalVerticalScrollBar   := MyVerticalScrollBarAdapter;
  Grid.ExternalHorizontalScrollBar := MyHorizontalScrollBarAdapter;
end;
// MyVerticalScrollBarAdapter / MyHorizontalScrollBarAdapter are controls that
// implement ITMSFNCDataGridExternalScrollBar.
void __fastcall TForm1::AssignExternalScrollBars()
{
  Grid->ExternalVerticalScrollBar   = MyVerticalScrollBarAdapter;
  Grid->ExternalHorizontalScrollBar = MyHorizontalScrollBarAdapter;
}

The interface requires: Value, Min, Max, PageSize, SmallChange, LargeChange, Visible, and OnChange. The grid drives all properties automatically; the implementation forwards them to the underlying scroll control.

Mouse-wheel scrolling

Grid.Options.Mouse controls wheel behaviour:

Mouse-wheel scrollingPascalC++
uses
  FMX.TMSFNCDataGrid;

procedure TForm1.ConfigureWheelScrolling;
begin
  Grid.Options.Mouse.WheelScrollSize          := 3;    // rows per tick
  Grid.Options.Mouse.WheelScrollKeepSelection := True; // don't move cursor on scroll
end;
void __fastcall TForm1::ConfigureWheelScrolling()
{
  Grid->Options->Mouse->WheelScrollSize          = 3;    // rows per tick
  Grid->Options->Mouse->WheelScrollKeepSelection = true; // don't move cursor on scroll
}

Wheel over a nested grid

When the pointer is over a subgrid — a detail grid in a master-detail layout, for example — the wheel scrolls that subgrid. If the subgrid is short enough that it needs no scrolling, the parent grid handles the wheel instead, so the outer list keeps moving rather than the gesture being swallowed by a detail panel that has nowhere to go.

Touch scrolling

Touch scrollingPascalC++
uses
  FMX.TMSFNCDataGrid;

procedure TForm1.ConfigureTouchScrolling;
begin
  Grid.Options.Mouse.TouchScrolling            := True; // enable swipe scroll
  Grid.Options.Mouse.TouchScrollingSensitivity := 5;    // pixels before scroll starts
end;
void __fastcall TForm1::ConfigureTouchScrolling()
{
  Grid->Options->Mouse->TouchScrolling            = true; // enable swipe scroll
  Grid->Options->Mouse->TouchScrollingSensitivity = 5;    // pixels before scroll starts
}

Auto-scroll while dragging

When the user drags a selection (or a row/column) past the edge of the visible area, the grid auto-scrolls:

Auto-scroll while draggingPascalC++
uses
  FMX.TMSFNCDataGrid;

procedure TForm1.ConfigureAutoScroll;
begin
  Grid.Options.Mouse.AutoScrolling         := True;
  Grid.Options.Mouse.AutoScrollingInterval := 50; // ms per tick
  Grid.Options.Mouse.AutoScrollingSpeed    := 2;  // rows/cols per tick
end;
void __fastcall TForm1::ConfigureAutoScroll()
{
  Grid->Options->Mouse->AutoScrolling         = true;
  Grid->Options->Mouse->AutoScrollingInterval = 50; // ms per tick
  Grid->Options->Mouse->AutoScrollingSpeed    = 2;  // rows/cols per tick
}

Combining scroll mode, events, and navigation

Scroll settings are rarely used alone. The scroll mode and update strategy decide how the grid moves and repaints, while the scroll events and programmatic navigation let your code follow or drive that movement. Combine them for a large grid with a position readout and a jump-to-row command. The example below switches to cell scrolling with a single repaint on release, tunes wheel and touch scrolling, reports the position in the form caption through the scroll events, and provides a method that scrolls to a given row while keeping the view position when the data is reloaded.

Combining scroll mode, events, and navigationPascalC++
procedure TForm1.FormCreate(Sender: TObject);
begin
  // How the grid moves and repaints
  Grid.ScrollMode := gsmCellScrolling;
  Grid.ScrollUpdate := gsuOnce;

  // Input devices
  Grid.Options.Mouse.WheelScrollSize := 3;
  Grid.Options.Mouse.TouchScrolling := True;

  // Follow the position
  Grid.OnVScroll := GridVScroll;
end;

procedure TForm1.GridVScroll(Sender: TObject; APosition: Single);
begin
  Caption := Format('V-scroll: %.0f', [APosition]);
end;

procedure TForm1.JumpToRow(ARow: Integer);
begin
  Grid.GoToCell(MakeCell(0, ARow));
end;

procedure TForm1.ReloadKeepingPosition;
begin
  Grid.Root.SaveScrollPosition;
  Grid.LoadFromCSVData('data.csv');
  Grid.Root.RestoreScrollPosition;
end;
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  // How the grid moves and repaints
  Grid->ScrollMode = gsmCellScrolling;
  Grid->ScrollUpdate = gsuOnce;

  // Input devices
  Grid->Options->Mouse->WheelScrollSize = 3;
  Grid->Options->Mouse->TouchScrolling = true;

  // Follow the position
  Grid->OnVScroll = GridVScroll;
}

void __fastcall TForm1::GridVScroll(TObject *Sender, float APosition)
{
  Caption = Format("V-scroll: %.0f", ARRAYOFCONST(((long double)APosition)));
}

void __fastcall TForm1::JumpToRow(int ARow)
{
  Grid->GoToCell(Fmx::Tmsfncdatagridcore::MakeCell(0, ARow));
}

void __fastcall TForm1::ReloadKeepingPosition()
{
  Grid->Root->SaveScrollPosition();
  Grid->LoadFromCSVData("data.csv");
  Grid->Root->RestoreScrollPosition();
}
  • Grid.ScrollMode, Grid.ScrollUpdate
  • Grid.Scroll(H, V), Grid.GoToCell(Cell)
  • Grid.GetHScrollValue / GetVScrollValue
  • Grid.Root.SaveScrollPosition / RestoreScrollPosition
  • OnHScroll, OnVScroll
  • Grid.CustomScrollBars, StretchScrollBars
  • Grid.HorizontalScrollBarVisible, Grid.VerticalScrollBarVisible
  • Grid.CustomHorizontalScrollBar, Grid.CustomVerticalScrollBar
  • Grid.ExternalHorizontalScrollBar, Grid.ExternalVerticalScrollBar
  • Grid.Options.Mouse.WheelScrollSize, WheelScrollKeepSelection
  • Grid.Options.Mouse.TouchScrolling, TouchScrollingSensitivity
  • Grid.Options.Mouse.AutoScrolling, AutoScrollingInterval, AutoScrollingSpeed

See also

  • Large datasets — gsuOnce and other patterns for big grids.
  • Keyboard & mouse — page-up/page-down navigation also drives scrolling.
  • Paging — paging is an alternative to long-scroll datasets.