How to Build a Grid That Adapts to Its Window

A paged grid normally has a fixed page size, which either overflows a small window or wastes a large one. Recalculating the page size from the visible area, while still offering a fixed size and an unpaged view, means writing the same geometry and paging code for every screen.

TVisualGrid in Sphere 10 Pascal Framework builds that choice into the control. Its PageMode property selects whether a page holds every row, the rows that fit the viewport, or a fixed number of rows. This article shows how to bind a data source, how each mode decides its page size, and what happens when the mode or the window changes.

A data grid adapting to the space available in its window.
A data grid adapting to the space available in its window.
💡 In short. Use TVisualGrid page modes to show all rows, a fixed page size or as many rows as fit the window, with one data source and one set of column bindings.

1. Bind one data source to three page modes

The grid reads its rows through the IDataSource interface. The simplest way to supply one is to derive from TCustomDataSource<T> and override three methods. GetColumns names the fields, FetchAll supplies the records, and GetItemField returns one field of one record as a Variant.

Pascal
  TItem = record
    Id: Integer;
    Name: String;
    Value: Integer;
  end;
  TItemSource = class(TCustomDataSource<TItem>)
  protected
    function GetColumns: TDataColumns; override;
    procedure FetchAll(const AContainer: TList<TItem>); override;
    function GetItemField({$IFDEF FPC}constref{$ELSE}const{$ENDIF} AItem: TItem; const ABindingName: String): Variant; override;
  end;

Each grid column is bound to a field name through its Binding property. Assigning DataSource connects the grid to the provider, and RefreshGrid requests the current page.

Pascal
    Grid.AddColumn('Id').Binding := 'Id';
    Grid.AddColumn('Name').Binding := 'Name';
    Grid.AddColumn('Value').Binding := 'Value';
    Grid.ManualPageSize := 25;
    Grid.PageMode := vpmManual;
    Grid.DataSource := Source;
    Grid.RefreshGrid;

After a fetch, RowCount reports the rows on the current page and Rows[I] returns a row whose fields are read by binding name, as in Grid.Rows[0].Id.

Existing Delphi/VCL Framework demonstration
Existing Delphi/VCL Framework demonstration

This retained screenshot is the repository's Delphi/VCL demonstration. The downloadable program is the separately executed LCL sample.

2. The three page modes

PageMode, which the binding code set to vpmManual, is a TVisualGridPageMode value. The mode only decides the page size that the grid requests. The data source and the column bindings are the same in every mode.

Mode Page size Paging controls
vpmManual (default) ManualPageSize, which defaults to 100 Shown
vpmAuto The number of complete rows that fit the current viewport Shown
vpmSingle All matching rows in one page Not needed

3. Let Auto follow the window

In vpmAuto the grid measures its own viewport and sets PageSize to the number of complete rows that fit. When the control is resized, the grid recalculates that capacity and requests the page again. The application writes no resize handler.

Pascal
    Grid.PageMode := vpmAuto;
    Window.Show;
    PumpLayout;
    Grid.RefreshGrid;
    PumpLayout;
    SmallCapacity := Grid.PageSize;
    Window.ClientHeight := 700;
    PumpLayout;
    Grid.RefreshGrid;
    PumpLayout;
    LargeCapacity := Grid.PageSize;

The capacity depends on native row height and on the grid having a parent with real bounds, so Auto only produces a meaningful size once the form is shown. A resize is applied after a short internal delay rather than on every size message. The sample's PumpLayout helper processes messages for a moment so that a console test can observe the settled value. A normal interactive form does not need it.

4. Switch modes at run time

PageMode can be changed at any time, and the grid's built-in paging menu changes the same property. A mode change does three things.

  • It returns to the first page.
  • It cancels a fetch that is still in flight, so an obsolete page cannot arrive after the switch.
  • It keeps ManualPageSize, so returning to vpmManual restores the size that was chosen earlier.
Pascal
    Grid.PageMode := vpmManual;
    Grid.RefreshGrid;
    if (Grid.ManualPageSize <> 25) or (Grid.RowCount <> 25) then
      raise Exception.Create('Manual size was not retained');

The older Boolean properties AutoPageSize and ShowAllData remain available and map onto the same state. Setting either to True selects vpmAuto or vpmSingle, and clearing it returns to vpmManual. ManualPageSize ignores values of zero or less.

5. What the page mode does not change

â„šī¸ A page mode is a presentation setting. The grid asks its data source for a page, and the data source decides how that page is produced.
âš ī¸ Keep these limits in mind.
  • TCustomDataSource<T> obtains its records through FetchAll and then filters, sorts and slices them in memory. A very large or remote dataset needs an IDataSource that pages at the source.
  • vpmSingle requests every matching row, so it suits result sets that are small enough to load at once.
  • Filtering and sorting apply to the whole result before a page is cut, in every mode. The snapshot paging article covers that query path and how to cache it.
  • The sample runs with FetchDataInThread := False so that each fetch completes before the next statement. Background fetching is covered in the latest-refresh article .

The visual grid unit is the reference for every grid property.

6. Get the Framework and run the example

Get Sphere 10 Pascal Framework and follow its package instructions . Use the units directly, or build the optional Lazarus or Delphi runtime package.

The sample was compiled and run on Windows with Free Pascal 3.2.0 and the Lazarus Win32 widgetset, against source revision 2cc6558 . Its Build.ps1 accepts the Framework, compiler, Lazarus and output paths. The program checks each mode and prints two lines.

Plain text
Manual: 25 rows per page; Single: 100 rows
Auto page size grew after resize; Manual returned to 25

Download the complete runnable sample.

sample.zip
Download the complete worked example and build instructions (ZIP).

For the broader Sphere 10 development toolkit, see the Sphere10 Framework overview .

Author: Herman Schoenfeld