Skip to main content

Overview

TVirtualData is an abstract base class that defines the interface for providing data to TeeGrid. It acts as a bridge between the grid and various data sources including databases, arrays, lists, and custom data structures.
TVirtualData is an abstract class. You must use one of its concrete implementations or create your own descendant class.

Concrete Implementations

TeeGrid includes several ready-to-use TVirtualData implementations:

TVirtualDBData

Unit: Tee.GridData.DBConnect to TDataSet and TDataSource for database data.

TVirtualArrayData<T>

Unit: Tee.GridData.RttiUse TArray<T> or TList<T> with RTTI for generic data.

TVirtualStringData

Unit: Tee.GridData.StringsString grid with Cells[Col, Row] interface like TStringGrid.

TBIGridData

Unit: BI.GridDataConnect to TeeBI TDataItem data structures.

Abstract Methods

These methods must be implemented in descendant classes.

Required Data Methods

Count
function
Returns the total number of rows in the data source.Signature:
function Count: Integer; virtual; abstract;
Returns: Total row count
AsString
function
Returns the string representation of data at the specified column and row.Signature:
function AsString(const AColumn: TColumn; const ARow: Integer): String; virtual; abstract;
Parameters:
  • AColumn - The column to read
  • ARow - The row index (0-based)
Returns: String representation of the cell value
SetValue
procedure
Updates the value at the specified column and row.Signature:
procedure SetValue(const AColumn: TColumn; const ARow: Integer;
                  const AText: String); virtual; abstract;
Parameters:
  • AColumn - The column to update
  • ARow - The row index (0-based)
  • AText - New value as string

Column Management

AddColumns
procedure
Automatically creates and adds columns to the grid based on the data structure.Signature:
procedure AddColumns(const AColumns: TColumns); virtual; abstract;
Parameters:
  • AColumns - The columns collection to populate
Load
procedure
Loads or refreshes column metadata from the data source.Signature:
procedure Load(const AColumns: TColumns); virtual; abstract;
Parameters:
  • AColumns - The columns collection to load
AutoWidth
function
Calculates the optimal width for a column based on its content.Signature:
function AutoWidth(const APainter: TPainter;
                  const AColumn: TColumn): Single; virtual; abstract;
Parameters:
  • APainter - Painter for measuring text
  • AColumn - Column to measure
Returns: Optimal width in pixels

State Methods

Empty
function
Checks if the data source is empty.Signature:
function Empty: Boolean; virtual; abstract;
Returns: True if no data is available
KnownCount
function
Indicates whether the total row count is known in advance.Signature:
function KnownCount: Boolean; virtual; abstract;
Returns: True if Count returns an accurate value, False if the count is unknown or approximate

Virtual Methods

These methods have default implementations but can be overridden for custom behavior.

Data Access

AsFloat
function
Returns the numeric value of data at the specified column and row.Signature:
function AsFloat(const AColumn: TColumn; const ARow: Integer): TFloat; virtual;
Returns: Numeric value (default implementation converts AsString to float)
DataType
function
Returns type information for the specified column.Signature:
function DataType(const AColumn: TColumn): PTypeInfo; virtual;
Returns: Pointer to RTTI type information, or nil if unknown

Editing

EditMode
procedure
Notifies the data source about edit mode changes.Signature:
procedure EditMode(const AMode: TEditMode); virtual;
Parameters:
  • AMode - Edit mode: Start, Cancel, or Finish
ReadOnly
function
Determines if a column is read-only.Signature:
function ReadOnly(const AColumn: TColumn): Boolean; virtual;
Returns: True if the column cannot be edited
ToggleBoolean
procedure
Toggles a boolean value at the specified location.Signature:
procedure ToggleBoolean(const AColumn: TColumn; const ARow: Integer);

Master-Detail

HasDetail
function
Checks if a row has expandable detail data.Signature:
function HasDetail(const ARow: Integer): Boolean; virtual;
Returns: True if the row can be expanded to show detail grid
GetDetail
function
Creates and returns a TVirtualData instance for detail data.Signature:
function GetDetail(const ARow: Integer; const AColumns: TColumns;
                  out AParent: TColumn): TVirtualData; virtual;
Parameters:
  • ARow - Master row index
  • AColumns - Columns for the detail grid
  • AParent - Returns the parent column for the relationship
Returns: TVirtualData instance for the detail data

Expansion

CanExpand
function
Determines if a row can be expanded.Signature:
function CanExpand(const Sender: TRender; const ARow: Integer): Boolean; virtual;
Returns: True if row expansion is supported

Sorting

CanSortBy
function
Checks if sorting by a column is supported.Signature:
function CanSortBy(const AColumn: TColumn): Boolean; virtual;
Returns: True if the column can be sorted
SortBy
procedure
Sorts data by the specified column.Signature:
procedure SortBy(const AColumn: TColumn); virtual;
IsSorted
function
Checks if data is currently sorted by a column.Signature:
function IsSorted(const AColumn: TColumn; out Ascending: Boolean): Boolean; virtual;
Parameters:
  • Ascending - Returns True if sorted ascending, False if descending
Returns: True if data is sorted by this column

Calculations

Calculate
function
Performs calculations on column data.Signature:
function Calculate(const AColumn: TColumn;
                  const ACalculation: TColumnCalculation): TFloat;
Parameters:
  • AColumn - Column to calculate
  • ACalculation - Type: Count, Sum, Min, Max, or Average
Returns: Calculated result

Sizing

AutoHeight
function
Calculates optimal height for a cell with multi-line content.Signature:
function AutoHeight(const APainter: TPainter; const AColumn: TColumn;
                   const ARow: Integer; out AHeight: Single): Boolean; virtual;
Returns: True if auto-height was calculated
LongestString
function
Measures the longest string in a column for auto-width calculation.Signature:
function LongestString(const APainter: TPainter;
                      const AColumn: TColumn): Single;
Returns: Width of longest string in pixels

State Management

EOF
function
Checks if a row index is beyond the end of data.Signature:
function EOF(const ARow: Integer): Boolean; virtual;
Returns: True if row index exceeds available data

Events and Callbacks

Protected Event Triggers

Refresh
procedure
Triggers the OnRefresh event to notify the grid of data changes.Signature:
procedure Refresh; virtual;
Repaint
procedure
Triggers the OnRepaint event to request a visual update.Signature:
procedure Repaint;
RowChanged
procedure
Notifies that a specific row’s data has changed.Signature:
procedure RowChanged(const ARow: Integer); virtual;
EditingChanged
procedure
Notifies about editing state changes.Signature:
procedure EditingChanged(const IsEditing: Boolean); virtual;

Event Properties

OnRefresh
TNotifyEvent
Fired when data needs to be refreshed from the source.
OnRepaint
TNotifyEvent
Fired when the grid needs to be repainted.
OnChangeRow
TRowChangedEvent
Fired when the current row changes.Signature:
procedure(const Sender: TObject; const ARow: Integer) of object;
OnEditing
TDataEditingEvent
Fired when editing starts or stops.Signature:
procedure(const Sender: TObject; const IsEditing: Boolean) of object;

Class Methods

From
class function
Factory method to create appropriate TVirtualData instance from a component.Signature:
class function From(const ASource: TComponent): TVirtualData; virtual;
Returns: TVirtualData instance or nil if source is not supported
IsNumeric
class function
Checks if a column contains numeric data.Signature:
class function IsNumeric(const AColumn: TColumn): Boolean; virtual;
Returns: True for numeric data types

Example: Custom TVirtualData Implementation

type
  TMyData = record
    Name: string;
    Age: Integer;
    Email: string;
  end;
  
  TMyDataArray = TArray<TMyData>;
  
  TMyVirtualData = class(TVirtualData)
  private
    FData: TMyDataArray;
  protected
    function Empty: Boolean; override;
    function KnownCount: Boolean; override;
  public
    constructor Create(const AData: TMyDataArray);
    
    procedure AddColumns(const AColumns: TColumns); override;
    function AsString(const AColumn: TColumn; const ARow: Integer): String; override;
    function AutoWidth(const APainter: TPainter; const AColumn: TColumn): Single; override;
    function Count: Integer; override;
    procedure Load(const AColumns: TColumns); override;
    procedure SetValue(const AColumn: TColumn; const ARow: Integer;
                      const AText: String); override;
  end;

implementation

constructor TMyVirtualData.Create(const AData: TMyDataArray);
begin
  inherited Create;
  FData := AData;
end;

function TMyVirtualData.Empty: Boolean;
begin
  Result := Length(FData) = 0;
end;

function TMyVirtualData.KnownCount: Boolean;
begin
  Result := True; // We know the exact count
end;

function TMyVirtualData.Count: Integer;
begin
  Result := Length(FData);
end;

procedure TMyVirtualData.AddColumns(const AColumns: TColumns);
begin
  AColumns.Add('Name');
  AColumns.Add('Age');
  AColumns.Add('Email');
end;

function TMyVirtualData.AsString(const AColumn: TColumn;
  const ARow: Integer): String;
begin
  if ARow < Length(FData) then
  begin
    if AColumn.Name = 'Name' then
      Result := FData[ARow].Name
    else if AColumn.Name = 'Age' then
      Result := IntToStr(FData[ARow].Age)
    else if AColumn.Name = 'Email' then
      Result := FData[ARow].Email;
  end;
end;

procedure TMyVirtualData.SetValue(const AColumn: TColumn;
  const ARow: Integer; const AText: String);
begin
  if ARow < Length(FData) then
  begin
    if AColumn.Name = 'Name' then
      FData[ARow].Name := AText
    else if AColumn.Name = 'Age' then
      FData[ARow].Age := StrToIntDef(AText, 0)
    else if AColumn.Name = 'Email' then
      FData[ARow].Email := AText;
    
    RowChanged(ARow);
  end;
end;

function TMyVirtualData.AutoWidth(const APainter: TPainter;
  const AColumn: TColumn): Single;
begin
  Result := LongestString(APainter, AColumn);
end;

procedure TMyVirtualData.Load(const AColumns: TColumns);
begin
  // No additional loading needed for in-memory array
end;

Registration

Register custom TVirtualData classes to enable automatic detection:
initialization
  TVirtualDataClasses.Register(TMyVirtualData);
  
finalization
  TVirtualDataClasses.UnRegister(TMyVirtualData);

See Also

TTeeGrid

Main grid component

TCustomTeeGrid

Abstract base grid class

Build docs developers (and LLMs) love