TTMSFNCDataGrid
Introduction
The TTMSFNCDataGrid
is a versatile and feature-rich data grid component in Delphi, part of the TMS FNC UI Pack
. This component is designed to handle large datasets efficiently while providing a customizable and user-friendly interface. It supports multiple platforms, including VCL
, FMX
, and Web
, making it a cross-platform solution for displaying tabular data. Key features of the TTMSFNCDataGrid
include sorting, filtering, editing, and grouping of data, as well as flexible cell formatting and the ability to embed various controls within cells. This makes it an essential tool for developers looking to create dynamic and interactive data-driven applications.
In addition to its core capabilities, the TTMSFNCDataGrid
is well-suited for implementing master-detail relationships, a common pattern in database-driven applications. A master-detail setup allows developers to link two grids or data sources, where the selection in the master grid (e.g., a list of orders) determines the data displayed in the detail grid (e.g., the items within a selected order).
Reference
When developing applications with the TTMSFNCDataGrid
, you'll encounter various classes, properties, methods, and events. Below is a list of the key classes that make up the data grid, which will help you navigate and utilize the most important ones effectively.
Getting Started
To start using the grid in your application, add it to a form:
- Open Your Project: Start by opening your Delphi or C++ Builder project.
- Locate the Component: In the Tool Palette, search for
TTMSFNCDataGrid
. - Drag and Drop: Drag the
TTMSFNCDataGrid
component from the Tool Palette onto your form.
Alternatively, you can create and add the grid programmatically:
var
Grid: TTMSFNCDataGrid;
begin
Grid := TTMSFNCDataGrid.Create(Self);
Grid.Parent := Self;
Grid.Align := TAlignLayout.Client;
end;
Basic Configuration
Once the grid is added to your form, you can configure its basic properties:
- Columns: Define the columns for your grid.
- Rows: Set the initial number of rows.
- Headers: Customize the column headers.
The basic structure of the grid is handled by the TTMSFNCDataGridCore
class.
Example: Basic Configuration
Grid.ColumnCount := 3;
Grid.RowCount := 5;
Grid.Columns[0].Header := 'ID';
Grid.Columns[1].Header := 'Name';
Grid.Columns[2].Header := 'Country';
Populating the Grid with Data
Populate the grid with data by accessing the cell data structure. Cell data is stored as TValue, which means that it can be any type of data you want.
Data manipulation and storage is handled by the TTMSFNCDataGridData
class.
Manual Data Entry
You can manually enter data into the grid by assigning values directly to specific cells.
Assigning Events
To interact with the grid or handle custom actions, you can assign events to the grid and handle them in your application.
Example: Cell Click event
procedure TForm1.GridCellClick(Sender: TObject; ACol, ARow: Integer);
begin
ShowMessage('Cell clicked at Column: ' + IntToStr(ACol) + ', Row: ' + IntToStr(ARow));
end;
Grid.OnCellClick := DoCellClick;
Changing the Grid look & feel
The grid presents cells according to details like font, color, size, text alignment, and other attributes. These settings can be customized in multiple ways.
Using CellAppearance
The CellAppearance property defines the layout for various cell states, such as selected, fixed, focused, and more, as well as for specific cell types like group node headers or summary footers. To modify the appearance, you can write:
The code above will modify the fill color of the focused cell layout.
Using Columns
The CellAppearance
property applies settings across the entire grid. However, at the column level, these settings can be overridden by specifying which particular settings need adjustment. This can be achieved using the following code:
Grid.Columns[1].Appearance.FocusedLayout.Fill.Color := gcRed;
Grid.Columns[1].AddSetting(gcsAppearance);
At design time, modifying properties in the columns editor will automatically apply the necessary overrides for the settings.
Using Cell Layouts
For more precise control over the appearance at the cell level, you can use Layouts. Similar to setting cell data, you can configure the Layouts property as follows:
Note that changing the layout at the cell level affects all states simultaneously, rather than allowing you to modify the appearance for each state individually.
Adding, Formatting & Converting Data
In the Getting Started section, we provided a sample for adding data and demonstrated how the grid can handle various data types and display formats. In this chapter, we'll explore in more detail how to add, format and convert data.
Basic Cell Data
Cell data is stored using the TValue
type, allowing it to hold any type of data. In the example above, we've inserted a number (1) and two strings. The grid will display the data exactly as it is in the corresponding cells. In the next sample, we've used a TDateTime & a floating point number.
You'll notice that the rendering is based on numerical values, as TDateTime
is represented as a Double
, with the default formatting displaying it as a decimal number. To change this formatting, you can either use the Formatting
property at the column level or handle it through the OnGetCellFormatting
event.
Grid.Columns[0].Formatting.&Type := gdftNumber;
Grid.Columns[0].Formatting.Format := '%.2f';
Grid.Columns[0].AddSetting(gcsFormatting);
Grid.Columns[1].Formatting.&Type := gdftDateTime;
Grid.Columns[1].AddSetting(gcsFormatting);
Setting Up OnGetCellFormatting
Event
To customize the cell formatting, handle the OnGetCellFormatting
event. This event is triggered for every cell that is rendered, and you can adjust the format based on the content.
Parameters
- ACell: Identifies the cell that is currently being formatted.
- AData: The actual data stored in the cell.
- AFormatting: Defines the format in which the cell's data will be displayed.
- AConvertSettings: A set of format settings (like date, number, currency formats) that can be adjusted to control the appearance of the data.
- ACanFormat: Allows or denies formatting of a cell. Set this to
True
to enable formatting.
Example: Applying Formatting to Different Data Types
Let’s apply custom formatting to a grid that holds various types of data, including names, dates, statuses, years of experience, and salaries.
Here’s how to handle the formatting in the OnGetCellFormatting
event for different data types:
Use Case
We have a grid with 5 columns:
- Name: Display names.
- Join Date: Display join dates in a specific format.
- Status: Display boolean values as custom text ("Approved" or "Pending").
- Years of Experience: Format numbers as integers.
- Salary: Format salary as a currency with two decimal points.
Formatting Rules
- Names: No special formatting applied.
- Join Date: Dates should be displayed in the format
yyyy/mm/dd
, with/
as the date separator. - Status: Booleans should be displayed as custom text—
True
as "Approved", andFalse
as "Pending". - Years of Experience: Format integers.
- Salary: Salaries should be displayed as currency, with two decimal places and a dollar sign (
$
).
Results in the Grid
- Name: No changes.
- Join Date: Dates like
2022/05/22
will display using theyyyy/mm/dd
format. - Status: Status values will be displayed as "Approved" for
True
and "Pending" forFalse
. - Years of Experience: Numbers like
5,5
will display as6
without decimals. - Salary: Salaries like
75000.5
will appear as$75,000.50
.
procedure TForm1.GridGetCellFormatting(Sender: TObject; ACell: TTMSFNCDataGridCellCoord;
AData: TTMSFNCDataGridCellValue; var AFormatting: TTMSFNCDataGridDataFormatting;
var AConvertSettings: TFormatSettings; var ACanFormat: Boolean);
begin
// Skip formatting for the first row (header row)
if ACell.Row = 0 then
Exit;
ACanFormat := True;
// Column 2: Format as date
if ACell.Column = 1 then
begin
AFormatting.Format := 'yyyy/mm/dd'; // Custom date format
AFormatting.&Type := gdftDate; // Set the formatting type to Date
AConvertSettings.ShortDateFormat := 'yyyy/mm/dd'; // Ensure date is displayed as yyyy/mm/dd
AConvertSettings.DateSeparator := '/'; // Use '/' as date separator
end;
// Column 3: Format as boolean with custom true/false text
if ACell.Column = 2 then
begin
AFormatting.&Type := gdftBoolean;
AFormatting.BooleanTrueText := 'Approved';
AFormatting.BooleanFalseText := 'Pending';
end;
// Column 4: Format as integer with a specific format
if ACell.Column = 3 then
begin
AFormatting.Format := '%g'; // Format numbers with commas for thousands
AFormatting.&Type := gdftNumber; // Set type to Number
end;
// Column 5: Format salary with two decimal points and currency symbol
if ACell.Column = 4 then
begin
AFormatting.Format := '#,##0.00'; // Format salary with commas and decimals
AFormatting.&Type := gdftFloat; // Set type to Float
AConvertSettings.CurrencyString := '$'; // Set currency symbol
AConvertSettings.DecimalSeparator := '.'; // Use '.' as the decimal separator
AConvertSettings.ThousandSeparator := ','; // Use ',' as the thousand separator
end;
end;
procedure TForm1.PopulateGrid;
begin
// Set the number of rows and columns
Grid.RowCount := 5; // 5 rows for more data
Grid.ColumnCount := 5; // 5 columns for different data types
// Add column headers
Grid.Cells[0, 0] := 'Name';
Grid.Cells[1, 0] := 'Join Date';
Grid.Cells[2, 0] := 'Status';
Grid.Cells[3, 0] := 'Years of Experience';
Grid.Cells[4, 0] := 'Salary';
// Add sample data to the grid
Grid.Cells[0, 1] := 'Jane Smith';
Grid.Cells[1, 1] := EncodeDate(2022, 5, 22); // Example join date
Grid.Cells[2, 1] := False; // Pending
Grid.Ints[3, 1] := 5; // Years of experience
Grid.Floats[4, 1] := 75000.50; // Salary with decimals
Grid.Cells[0, 2] := 'John Doe';
Grid.Cells[1, 2] := EncodeDate(2019, 7, 10); // Example join date
Grid.Cells[2, 2] := True; // Approved
Grid.Ints[3, 2] := 8; // Years of experience
Grid.Floats[4, 2] := 85000.75; // Salary with decimals
Grid.Cells[0, 3] := 'Alice Brown';
Grid.Cells[1, 3] := EncodeDate(2021, 11, 3); // Example join date
Grid.Cells[2, 3] := False; // Pending
Grid.Ints[3, 3] := 3; // Years of experience
Grid.Floats[4, 3] := 62000.00; // Salary with no decimals
Grid.Cells[0, 4] := 'Bob Johnson';
Grid.Cells[1, 4] := EncodeDate(2018, 9, 15); // Example join date
Grid.Cells[2, 4] := True; // Approved
Grid.Ints[3, 4] := 12; // Years of experience
Grid.Floats[4, 4] := 95000.00; // Salary with no decimals
Grid.AutoSizeGrid();
end;
Converting Data
Since TTMSFNCDataGrid stores its cell data using the versatile TValue
type, it’s easy to convert between different data types when needed. You can use built-in functions to convert TValue
to specific types, such as integers, floats, booleans, and strings
:
- Convert to Integer:
TValue.ToInteger
- Convert to String:
TValue.ToString
- Convert to Float:
TValue.ToFloat
- Convert to Boolean:
TValue.ToBoolean
Example:
var
Value: TValue;
IntValue: Integer;
StrValue: String;
begin
Value := Grid.Cells[1, 1]; // Fetch cell data as TValue
if Value.IsInteger then
IntValue := Value.AsInteger;
StrValue := Value.AsString; // Convert to string
end;
This flexibility allows you to retrieve and manipulate data in the format you need for calculations, validations, or display purposes.
Converting String Data to Dates
Another frequent need is to convert string representations of dates into TDateTime
values. This is common when loading data from external sources, where dates are often stored as strings in various formats.
Example: Converting String Data to TDateTime
Using ConvertSettings
If your grid contains date values stored as strings (e.g., "31-12-2023"
), you can use the ConvertSettings
to transform these strings into TDateTime
values that the grid will display properly:
procedure TForm1.GridGetCellFormatting(Sender: TObject; ACell: TTMSFNCDataGridCellCoord;
AData: TTMSFNCDataGridCellValue; var AFormatting: TTMSFNCDataGridDataFormatting;
var AConvertSettings: TFormatSettings; var ACanFormat: Boolean);
begin
// Column 1 is expected to contain date data in string format
if ACell.Column = 1 then
begin
AConvertSettings.ShortDateFormat := 'dd-mm-yyyy'; // Define the input date format
AConvertSettings.DateSeparator := '-'; // Specify the date separator
AFormatting.Format := 'yyyy/mm/dd'; // Format the output as yyyy/mm/dd
AFormatting.&Type := gdftDate; // Indicate the data should be treated as a date
ACanFormat := True; // Allow the formatting to proceed
end;
end;
Here, the ConvertSettings define how to interpret the input string ("31-12-2023")
and convert it into a TDateTime
value. The grid will then display the date in the yyyy/mm/dd
format, even though the input was in a different string format.
Editing
To enable editing in TTMSFNCDataGrid
, you need to ensure that editing capabilities are properly configured. The grid provides various options for enabling and handling cell editing, both through user interaction and programmatically.
Here's a guide to enable and handle editing:
Enable Editing
Make sure the Options.Editing.Enabled
property is set to True
to allow cell editing.
procedure TForm1.FormCreate(Sender: TObject);
begin
// Enable editing
Grid.Options.Editing.Enabled := True;
end;
Enable Different Editor Types
The TTMSFNCDataGrid
supports various types of editors, such as text editors, dropdown lists, date pickers, etc.
To specify the editor type for a particular column:
Grid.ColumnCount := 10;
// Example: Set a date picker editor for column 4
Grid.Columns[4].Editor := getDatePicker;
Grid.Columns[4].AddSetting(gcsEditor);
// Example: Set a color picker editor for column 5
Grid.Columns[5].Editor := getColorPicker;
Grid.Columns[5].AddSetting(gcsEditor);
// Example: Set a trackbar (slider) editor for column 6
Grid.Columns[6].Editor := getTrackBar;
Grid.Columns[6].AddSetting(gcsEditor);
List of Editor Types
Below is a list of editor types used in combination with the Editor property at column level, or via the OnGetInplaceEditorType event
- getEdit :Default inplace editor, edit cell values based on strings
- getNumericEdit : Edit cell values based on numbers
- getSignedNumericEdit : Edit cell values specifically based on positive or negative numbers
- getFloatEdit : Edit cell values based on floating point numbers
- getSignedFloatEdit : Edit cell values specifically based on positive or negative floating point numbers
- getUppercaseEdit : Edit cell values with Uppercase string values
- getMixedCaseEdit : Edit cell values with Mixed case string values
- getLowerCaseEdit : Edit cell values with Lower case string values
- getMoneyEdit : Edit cell values formatted as Money numbers
- getHexEdit : Edit cell values formatted as hex strings
- getAlphaNumericEdit : Edit cell values containing only alpha or numeric characters
- getValidCharsEdit : Edit cell values containing only a set of valid characters
- getComboBox :Edit cell values with a combobox
- getComboEdit :Edit cell values with a editable combobox
- getSpinBox : Edit cell values with a spin box
- getDatePicker : Edit cell values with a date picker
- getColorPicker : Edit cell values with a color picker
- getTrackBar : Edit cell values with a trackbar
- getMemo : Edit cell values containing multi-line strings
- getHTMLEditor : Edit cell values containing HTML in a separate editor
- getCustom : Specify your own editor and set it up in the OnGetInplaceEditorClass event
Populate Dropdown Editor
If you're using a dropdown editor (combobox), you need to supply the items for the editor:
Grid.Columns[1].Editor := getComboBox;
Grid.Columns[1].AddSetting(gcsEditor);
Grid.Columns[1].EditorItems.Add('John Doe');
Grid.Columns[1].EditorItems.Add('Caroline Dover');
Grid.Columns[1].EditorItems.Add('Loena Vandamme');
Grid.Columns[1].AddSetting(gcsEditorItems);
Custom Editor
The possibility exists to use a custom editor. To implement this, etCustom must be set to the var parameter in the OnGetCellEditorType event. For this sample we have used a TTreeView item in a cell that has a modified columnwidth and rowheight:
Grid.ColumnWidths[4] := 150;
Grid.RowHeights[4] := 100;
procedure TForm1.TMSFNCDataGrid1GetInplaceEditorType(Sender: TObject;
ACell: TTMSFNCDataGridCellCoord;
var AInplaceEditorType: TTMSFNCDataGridInplaceEditorType);
begin
AInplaceEditorType := getCustom;
end;
To specify which editor the custom type is, the OnGetInplaceEditorClass must be implemented, returning the editor type of choice.
procedure TForm1.TMSFNCDataGrid1GetInplaceEditorClass(Sender: TObject;
ACell: TTMSFNCDataGridCellCoord;
var AInplaceEditorClass: TTMSFNCDataGridInplaceEditorClass);
begin
AInplaceEditorClass := TTreeView;
end;
Additional properties, items, appearance can be added to the custom editor in the OnGetInplaceEditorProperties event.
procedure TForm1.TMSFNCDataGrid1GetInplaceEditorProperties(Sender: TObject;
ACell: TTMSFNCDataGridCellCoord; AInplaceEditor: TTMSFNCDataGridInplaceEditor;
AInplaceEditorType: TTMSFNCDataGridInplaceEditorType);
var
tParent, tGroup, tItem: TTreeViewItem;
begin
tParent := TTreeViewItem.Create(AInplaceEditor);
tParent.Text := 'Fruits';
AInplaceEditor.AddObject(tParent);
tGroup := TTreeViewItem.Create(AInplaceEditor);
tGroup.Text := 'Red Fruits';
tParent.AddObject(tGroup);
tItem := TTreeViewItem.Create(AInplaceEditor);
tItem.Text := 'StrawBerry';
tGroup.AddObject(tItem);
tItem := TTreeViewItem.Create(AInplaceEditor);
tItem.Text := 'Cherry';
tGroup.AddObject(tItem);
tGroup := TTreeViewItem.Create(AInplaceEditor);
tGroup.Text := 'Green Fruits';
tParent.AddObject(tGroup);
tItem := TTreeViewItem.Create(AInplaceEditor);
tItem.Text := 'Apple';
tGroup.AddObject(tItem);
tItem := TTreeViewItem.Create(AInplaceEditor);
tItem.Text := 'Lime';
tGroup.AddObject(tItem);
end;
To bind the treeview to the cell, we need the OnCellEditGetData & OnCellEditSetData
procedure TForm1.TMSFNCDataGrid1CellEditGetData(Sender: TObject;
ACell: TTMSFNCDataGridCellCoord; AInplaceEditor: TTMSFNCDataGridInplaceEditor;
var AValue: TTMSFNCDataGridCellValue);
begin
(AInplaceEditor as TTreeView).Selected := (AInplaceEditor as TTreeView).ItemByText(AValue.AsString);
end;
procedure TForm1.TMSFNCDataGrid1CellEditSetData(Sender: TObject;
ACell: TTMSFNCDataGridCellCoord; AInplaceEditor: TTMSFNCDataGridInplaceEditor;
var AValue: TTMSFNCDataGridCellValue);
begin
AValue := (AInplaceEditor as TTreeView).Selected.Text;
end;
When clicking in the cell to start the editor, the treeview is shown.
Validating Input
To validate user input before saving the changes, you can use the OnCellEditValidateData
event:
procedure TForm1.GridCellEditValidateData(Sender: TObject;
ACell: TTMSFNCDataGridCellCoord; AInplaceEditor: TTMSFNCDataGridInplaceEditor;
var AValue: TTMSFNCDataGridCellValue; var AValid: Boolean);
var
i: Integer;
begin
// Example: Allow only numeric values in column 2
if ACell.Column = 2 then
begin
if not TryStrToInt(Grid.ValueToString(AValue), i) then
begin
AValid := False;
ShowMessage('Invalid input. Please enter a number.');
end;
end;
end;
Grid Cell Merging / Splitting
The grid supports merging and splitting cells programmatically as well as with the keyboard. To merge a range of cells simple call
Sample:To split the merged cells, you can use the procedure grid.SplitCell. The parameters passed in the procedure need to be the base cell of the range of merged cells.
Sample:
When enabled via Grid.Options.Keyboard.CellMergeShortCut
, the following shortcuts invoke a merge & split of the selected cells:
Selection
TTMSFNCDataGrid
provides flexible selection options to enable users to select individual cells, multiple cells, rows, or columns. This guide walks you through enabling and handling selection behavior in TTMSFNCDataGrid
.
Selection Modes
The TTMSFNCDataGrid
provides several selection modes, each offering different ways to select cells:
- gsmNone : Disables selection, but other interactions remain active.
- gsmSingleCell : Selects a single cell at a time. The previously selected cell is deselected.
- gsmSingleRow : Selects an entire row. Previous row selection is cleared when a new row is selected.
- gsmSingleColumn : Selects an entire column. Previous column selection is cleared when a new column is selected.
- gsmCellRange : Allows selecting multiple cells. Holding
Shift
while clicking selects a range of cells. Dragging the mouse across the grid also selects multiple cells. - gsmRowRange : Allows selecting multiple rows. Holding
Shift
selects a range of rows between the clicked row and the previously selected row. - gsmColumnRange : Allows selecting multiple columns. Holding
Shift
selects a range of columns. - gsmDisjunctRow : Similar to
gsmRowRange
, but allows selecting non-contiguous rows usingCtrl
. - gsmDisjunctColumn : Similar to
gsmColumnRange
, but allows selecting non-contiguous columns usingCtrl
. - gsmDisjunctCell : Allows selecting non-contiguous cells using
Ctrl
. - gsmDisjunctCellRange : Allows selecting non-contiguous cells using
Ctrl
andShift
in an explorer type selection mode.
Programmatically Setting Selection
You can set the selection programmatically using the Selection
property. For example, in gsmCellRange
mode, to select a range of cells from (3,3) to (4,4), use:
In gsmSingleCell
mode, to select a single cell (e.g., (3,3)):
Working with Row Selection in gsmDisjunctRow
The SelectedRows[RowIndex]: Boolean
property allows you to check or set the selection state of a row.
var
i: Integer;
begin
for i := 0 to Grid.RowCount - 1 do
begin
if Grid.SelectedRows[i] then
begin
// Process the selected row
// For example paint the row in a color
end;
end;
end;
Column and Cell Selection
Similar to rows, the gsmDisjunctColumn
and gsmDisjunctCell
modes allow disjoint selection of columns and cells. You can use the following properties:
- Column Selection: Use
SelectedColumns[columnindex]: Boolean
,SelectedColumnCount
, to work with column selections. - Cell Selection: Use
SelectedCells[col,row: Integer]: Boolean
,SelectedCellCount
, to work with individual cell selections.
Example for looping through all selected cells:
Fixed Cell Selection
In combination with the Options.Selection.Mode
, the grid supports selection when clicking or dragging on fixed cells. This behavior can be enabled using the Options.Mouse.FixedCellSelection
property.
- gfcsAll: Clicking the top-left fixed cell selects all cells in the grid (with
gsmCellRange
). - gfcsRow: Clicking and dragging on the fixed columns selects rows (with
gsmSingleRow
). - gfcsColumn: Clicking and dragging on the fixed rows selects columns (with
gsmSingleColumn
). - gfcsRowRange: Clicking and dragging on the fixed columns selects multiple rows (with
gsmRowRange
). - gfcsColumnRange: Clicking and dragging on the fixed rows selects multiple columns (with
gsmColumnRange
).
Note: If column dragging, row dragging, or sorting is enabled, fixed cell selection mode is automatically disabled.
Calculations
The grid has built-in methods to perform calculations on all rows or a selected range of rows within a column. These functions return a result when called. Additionally, the grid provides automatic column calculations that are displayed in a footer row and updated when cell values change through editing.
Built-in Row Calculation Functions
Grid.RowAverage(ARow: Integer; FromCol: Integer = -1; ToCol: Integer = -1): Double
- Purpose: Calculates the average of values in a specified row.
- Parameters:
ARow
: The index of the row.FromCol
: The starting column for the calculation (optional, defaults to all columns if set to-1
).ToCol
: The ending column for the calculation (optional, defaults to all columns if set to-1
).- Return Value: The average of the row values for the specified range of columns.
Grid.RowCustomCalculation(ARow: Integer; FromCol: Integer = -1; ToCol: Integer = -1): Double
- Purpose: Performs a custom calculation on the values in a row.
- Trigger: Triggers the event
OnRowCalc
, where the custom calculation logic can be implemented.
Grid.RowDistinct(ARow: Integer; FromCol: Integer = -1; ToCol: Integer = -1): Double
- Purpose: Counts the number of distinct (unique) values in a specified row.
Grid.RowMax(ARow: Integer; FromCol: Integer = -1; ToCol: Integer = -1): Double
- Purpose: Finds the maximum value in a specified row.
Grid.RowMin(ARow: Integer; FromCol: Integer = -1; ToCol: Integer = -1): Double
- Purpose: Finds the minimum value in a specified row.
Grid.RowStandardDeviation(ARow: Integer; FromCol: Integer = -1; ToCol: Integer = -1): Double
- Purpose: Calculates the standard deviation of values in a specified row.
Grid.RowSum(ARow: Integer; FromCol: Integer = -1; ToCol: Integer = -1): Double
- Purpose: Calculates the sum of values in a specified row.
Built-in Column Calculation Functions
Grid.ColumnSum(ACol: Integer; FromRow: Integer = -1; ToRow: Integer = -1): Double
- Purpose: Calculates the sum of values in a column.
- Parameters:
- ACol
: The index of the column.
- FromRow
: The starting row for the calculation (optional, defaults to all rows if set to -1
).
- ToRow
: The ending row for the calculation (optional, defaults to all rows if set to -1
).
- Return Value: The sum of the column values for the specified range of rows.
Grid.ColumnAverage(ACol: Integer; FromRow: Integer = -1; ToRow: Integer = -1): Double
- Purpose: Calculates the average of cell values in a column.
Grid.ColumnMin(ACol: Integer; FromRow: Integer = -1; ToRow: Integer = -1): Double
- Purpose: Returns the minimum value in a specified column.
Grid.ColumnMax(ACol: Integer; FromRow: Integer = -1; ToRow: Integer = -1): Double
- Purpose: Returns the maximum value in a specified column.
Grid.ColumnDistinct(ACol: Integer; FromRow: Integer = -1; ToRow: Integer = -1): Double
- Purpose: Counts the number of distinct (unique) cell values in a column.
Grid.ColumnStandardDeviation(ACol: Integer; FromRow: Integer = -1; ToRow: Integer = -1): Double
- Purpose: Calculates the standard deviation of cell values in a column.
Grid.ColumnCustomCalculation(ACol: Integer; FromRow: Integer = -1; ToRow: Integer = -1): Double
- Purpose: Performs a custom calculation on the values in a column.
Built-in Automatic Column Calculations in the Footer Row
Using the ColumnCalculations[Col, Name]
property, you can specify the type of calculation that should be displayed in a footer row for each column. The available options are:
gcmNone
: No result is displayed in the footer cell.gcmSum
: Displays the sum of the column.gcmAvg
: Displays the average of the column.gcmCount
: Displays the row count of the column.gcmMin
: Displays the minimum value of the column.gcmMax
: Displays the maximum value of the column.gcmCustom
: Displays a custom calculation result for the column.gcmDistinct
: Displays the count of distinct values in the column.gcmStdDev
: Displays the standard deviation of the column.
Programmatically Updating Calculations
When cell values are updated programmatically, the calculations can be updated using:
-
Grid.UpdateCalculations
Updates all column calculations. -
Grid.UpdateColumnCalculation(ColumnIndex: Integer)
Updates the calculation for the specified column. -
Grid.UpdateRowCalculation(RowIndex: Integer)
Updates the calculation for the specified row.
Example
Here is an example of how to initialize the grid and set up column calculations:
Grid.RowCount := 20;
Grid.FixedBottomRowCount := 1;
Grid.RandomFill(False, 100);
Grid.ColumnCalculations[0, 'SUM'] := [CreateNormalColumnCalculation(gcmSum)];
Grid.ColumnCalculations[1, 'AVERAGE'] := [CreateNormalColumnCalculation(gcmAverage)];
Grid.ColumnCalculations[2, 'MIN'] := [CreateNormalColumnCalculation(gcmMin)];
Grid.ColumnCalculations[3, 'MAX'] := [CreateNormalColumnCalculation(gcmMax)];
Grid.UpdateCalculations;
Upon running the application, the footer row will display the specified calculations for each column. Automatic Row Calculations can be applied in a similar way but in combination with FixedRightColumnCount. When grouping, Column or Row Calculations can be created based on individual groups, use the CreateGroupColumnCalculation or CreateGroupRowCalculation instead.
Cell Controls
Built-in Cell Control Methods
The following methods are available to add or manage controls in grid cells:
-
Grid.AddButton(AColumn, ARow: Integer; AText: string = '')
Adds a button control to the specified cell. -
Grid.AddCheckBox(AColumn, ARow: Integer; AValue: Boolean = False)
Adds a checkbox control to the specified cell. -
Grid.AddRadioButton(AColumn, ARow: Integer; AValue: Boolean = False; AGroupIndex: Integer = 0)
Adds a radio button control to the specified cell, allowing selection from a group of radio buttons. -
Grid.AddProgressBar(AColumn, ARow: Integer; AValue: Integer = 0)
Adds a progress bar control to the specified cell. -
Grid.AddDataCheckBox(AColumn, ARow: Integer)
Adds a data-bound checkbox control to the specified cell, allowing it to bind to grid data. -
Grid.AddDataRadioButton(AColumn, ARow: Integer; AValue: Boolean = False; AGroupIndex: Integer = 0)
Adds a data-bound radio button control to the specified cell. -
Grid.AddDataProgressBar(AColumn, ARow: Integer)
Adds a data-bound progress bar control to the specified cell, enabling it to update dynamically based on grid data. -
Grid.RemoveButton(AColumn, ARow: Integer)
Removes the button control from the specified cell. -
Grid.RemoveCheckBox(AColumn, ARow: Integer)
Removes the checkbox control from the specified cell. -
Grid.RemoveProgressBar(AColumn, ARow: Integer)
Removes the progress bar control from the specified cell.
This is an example from a demo with multiple things from the list above:
These are other examples of Cell Controls:
Control Properties
Each control has properties that allow customization:
-
ControlWidths[AColumn, ARow]: Integer
Defines the width of the control inside the cell. -
ControlHeights[AColumn, ARow]: Integer
Defines the height of the control inside the cell. -
ControlAligns[AColumn, ARow]: TTMSFNCDataGridCellControlAlign
Sets the alignment of the control within the cell. -
ControlTexts[AColumn, ARow]: string
Defines the text displayed on the control (applies to buttons, checkboxes, etc.). -
ControlPositions[AColumn, ARow]: TTMSFNCDataGridCellControlPosition
Sets the position of the control inside the cell.
Example of Adding Controls
Here is a code snippet demonstrating how to add various controls to a grid:
// Add a button to cell (1, 1)
Grid.AddButton(1, 1, 'Click Me');
// Add a checkbox to cell (2, 2) with a default value of False
Grid.AddCheckBox(2, 2, False);
// Add a radio button to cell (3, 3), part of group 1
Grid.AddRadioButton(3, 3, True, 1);
// Add a progress bar to cell (4, 4) with a default value of 50
Grid.AddProgressBar(4, 4, 50);
// Customize control properties
Grid.ControlWidths[1, 1] := 100;
Grid.ControlAligns[1, 1] := gcaTop;
Updating and Removing Controls
To update or modify existing controls programmatically:
-
Grid.SetButton(AColumn, ARow: Integer; AText: string = '')
Updates or replaces the button at the specified cell. -
Grid.SetCheckBox(AColumn, ARow: Integer; AValue: Boolean = False)
Updates or replaces the checkbox at the specified cell.
To remove a control from a cell:
// Remove the button from cell (1, 1)
Grid.RemoveButton(1, 1);
// Remove the checkbox from cell (2, 2)
Grid.RemoveCheckBox(2, 2);
Control Events
The grid provides events that can be triggered when controls are interacted with:
-
OnCellButtonClick
Triggered when a button in a cell is clicked. -
OnCellCheckBoxChange
Triggered when the value of a checkbox in a cell changes. -
OnCellRadioButtonChange
Triggered when a radio button in a cell changes state.
Example of Handling Control Events
procedure TForm1.GridCellButtonClick(Sender: TObject; AColumn, ARow: Integer);
begin
ShowMessage('Button in cell (' + IntToStr(AColumn) + ', ' + IntToStr(ARow) + ') clicked.');
end;
procedure TForm1.GridCellCheckBoxChange(Sender: TObject; AColumn, ARow: Integer);
begin
if Grid.Booleans[AColumn, ARow] then
ShowMessage('Checkbox in cell (' + IntToStr(AColumn) + ', ' + IntToStr(ARow) + ') is checked.')
else
ShowMessage('Checkbox in cell (' + IntToStr(AColumn) + ', ' + IntToStr(ARow) + ') is unchecked.');
end;
Custom Cell Drawing
Each cell supports custom drawing via an event. With the events OnBeforeDrawCell
and OnAfterDrawCell
you can custom draw on a cell, or complete column / row of choice that can be retrieved by using the ACell.Row and ACell.Column parameters. Below is a sample that draws a diagonal line as a background which replaces the default background of a cell on location 3, 3
.
procedure TForm1.GridAfterDrawCell(Sender: TObject; AGraphics: TTMSFNCGraphics;
ACell: TTMSFNCDataGridCell);
begin
if (ACell.Column = 3) and (ACell.Row = 3) then
begin
AGraphics.SetStrokeColor(gcRed);
AGraphics.DrawLine(PointF(ACell.Rect.Left, ACell.Rect.Top),
PointF(ACell.Rect.Right, ACell.Rect.Bottom));
end;
end;
Customize Cell Elements
Each cell supports a set of elements that are determining what is being drawn. For example, if it's required to only export the text & stroke during PDF generation, it's possible to customize this via the DrawElements property. To implement this, use the OnBeforeDrawCell event with the following code.
procedure TForm1.GridBeforeDrawCell(Sender: TObject;
AGraphics: TTMSFNCGraphics; ACell: TTMSFNCDataGridCell;
var ACanDraw: Boolean);
begin
if ACell.IsExporting then
ACell.DrawElements := [gcdText, gcdStroke];
end;
Custom Cell Classes
TTMSFNCDataGrid
provides a variety of cell classes to handle different types of content and behavior within the grid. These classes inherit from the base TTMSFNCDataGridCell
class and allow for customizations such as node management, checkboxes, buttons, and progress bars.
By default, the Grid automatically handles the required cell class but in some cases, it might be required to customize this. This chapter covers the available cell classes and how to implement them using the OnGetCellClass
event.
TTMSFNCDataGridCell
(Base Class)
TTMSFNCDataGridCell
is the fundamental class that all other cell types in TTMSFNCDataGrid
are based on. It manages the basic functionality, such as rendering the cell's content and handling user interactions.
Key Properties:
Rect: TRectF
: Defines the boundaries of the cell.Column
andRow
: Integer: Specify the location of the cell within the grid.Text: string
: Holds the cell's content.Control
: TTMSFNCDataGridCellControl: Specifies any controls embedded within the cell (for example, buttons or checkboxes).
You can use the base cell class when you don’t need any special controls or custom behavior in a grid cell.
TTMSFNCDataGridNodeCell
This cell class is used to represent a node in a hierarchical grid. Nodes can be collapsed or expanded, and they can have child rows, creating a tree-like structure within the grid.
Key Features:
State: TTMSFNCDataGridRowNodeState
: Manages whether the node is expanded or collapsed.IconPosition: TTMSFNCDataGridNodeCellIconPosition
: Controls the placement of the expand/collapse icon.
Use this class when implementing hierarchical data that needs collapsible rows or tree structures.
TTMSFNCDataGridCheckBoxCell
This cell type includes a checkbox that can be toggled by the user. It is ideal for displaying boolean values or selecting rows.
Key Features:
Checked: Boolean
: Determines the state of the checkbox (checked or unchecked).OnChange: TNotifyEvent
: Fires when the checkbox state changes.
Use this class when you need checkboxes in your grid cells, such as for selection or boolean options.
TTMSFNCDataGridButtonCell
This cell type includes a clickable button. When clicked, the button triggers an event.
Key Features:
OnClick: TNotifyEvent
: Event that is triggered when the button is clicked.Text: string
: The label of the button.
Use this class for cells that require user interaction via buttons, such as "Edit" or "Delete" actions.
TTMSFNCDataGridProgressBarCell
This cell class displays a progress bar, allowing you to visualize the progress of tasks or processes.
Key Features:
Value: Integer
: Represents the progress percentage (0-100).Max: Integer
: The maximum value for the progress bar.
Use this class when you need to show progress within a cell, such as task completion or loading indicators.
TTMSFNCDataGridBitmapCell
This cell type allows you to display images inside the grid. It supports loading and displaying bitmaps.
Key Features:
Bitmap: TTMSFNCBitmap
: The image to be displayed in the cell.BitmapAlign: TTMSFNCDataGridCellControlAlign
: Controls the alignment of the bitmap within the cell.
Use this class to display images or icons in grid cells, such as product images, profile pictures, or status icons.
Implementing Cell Classes via OnGetCellClass
To dynamically assign a specific cell class to a grid cell, the OnGetCellClass
event is used. This event allows you to specify the class type of the cell based on the row or column, enabling custom cell behavior per cell or row.
Event Handler Implementation
In the OnGetCellClass
event, you can switch between different cell types based on the column or row index. This is particularly useful for grids with heterogeneous data types.
Example of Setting Different Cell Classes
The following example demonstrates how to assign different cell classes dynamically:
procedure TForm1.GridGetCellClass(Sender: TObject; ACol, ARow: Integer; var CellClassType: TTMSFNCDataGridCellClass);
begin
if ACol = 1 then
CellClassType := TTMSFNCDataGridCheckBoxCell
else if ACol = 2 then
CellClassType := TTMSFNCDataGridButtonCell
else if ACol = 3 then
CellClassType := TTMSFNCDataGridProgressBarCell
else
CellClassType := TTMSFNCDataGridCell; // Default
end;
Import & Export
Files
procedure SaveToFileData(AFileName: String; AEncoding: TEncoding);
procedure LoadFromFileData(AFileName: String; AEncoding: TEncoding);
SaveToFileData
saves cell data and column widths to a proprietary file format, while LoadFromFileData
loads cell data and column widths from the same format. Both methods can optionally be specified with a particular encoding.
CSV files
procedure SaveToCSVData(AFileName: String; AEncoding: TEncoding);
procedure LoadFromCSVData(AFileName: String; AEncoding: TEncoding);
SaveToCSVData
saves cell data to a CSV file, while LoadFromCSVData
loads cell data from a CSV file.
Several properties impact the CSV methods:
This specifies the delimiter to use when saving to and loading from CSV files. By default, the delimiter is set to#0
, which allows for automatic delimiter detection when loading data from a CSV file. When saving to a CSV file, the ;
character is used as the separator if the delimiter is set to #0
. Setting the delimiter to a value other than #0
forces the CSV functions to use the specified delimiter exclusively.
When set to true, an empty cell in the CSV file is saved as ""
. If false, no characters are written for empty cells.
When set to true, every cell value is saved with both prefix and suffix quotes. If false, quotes are only used when the cell data contains the delimiter character. Additionally, if the cell data includes quotes, they are written as doubled quotes in the file.
By default, data is loaded into the grid starting from the first normal cell, which is typically cell 1,1 (considering there is one fixed row and one fixed column). To override this default behavior and specify a different starting cell for loading data, you can use the public properties:
HTML files
SaveToHTMLData
saves cell data to an HTML file, utilizing Grid.Options.IO.HTML
for various export settings. The cell data is formatted and saved within an HTML table.
PDF Files
Drop a TTMSFNCDataGridPDFIO component on the form and connect the TTMSFNCDataGrid to this non-visual component’s DataGrid property.
Alternatively, the TMSFNCDataGridPDFIO
component can save to a stream by calling the Save
method with a TStream
instance. Additionally, the component allows for configuring margins, headers, footers, and PDF metadata such as creator, author, title, and keywords. These settings can be adjusted under the Options
and Information
properties.
PDF Export example
XLS files
With the TTMSFNCDataGridExcelIO
component, you can easily read from and write to Excel .XLS
files without needing Excel installed on your machine.
To use TTMSFNCDataGridExcelIO
for importing or exporting XLS files, follow these steps:
- Drop both the
TTMSFNCDataGrid
andTTMSFNCDataGridExcelIO
components onto your form. - Assign the
TTMSFNCDataGrid
instance to theDataGrid
property of theTTMSFNCDataGridExcelIO
component. - Configure the
TTMSFNCDataGridExcelIO
properties to control the Excel file read/write behavior, although the default settings are usually sufficient. - To import an Excel file, use:
To export the contents of TTMSFNCDataGrid to an XLS file use:
orProperties of TTMSFNCDataGridExcelIO
Many properties are available in TTMSFNCDataGridExcelIO to customize importing & exporting of Excel files in the grid.
Property name | Description |
---|---|
AutoResizeGrid: Boolean; | When true, the dimensions of the grid (ColCount, RowCount) will adapt to the number of imported cells. |
DateFormat: string; | Sets the format of dates to use for imported dates from the Excel file. When empty, the default system date formatting is applied. |
GridStartCol, GridStartRow: integer; | Specifies from which top/left column/row the import/export happens |
Options.ExportCellFormats: Boolean; | When true, cell format (string, integer, date, float) is exported, otherwise all cells are exported as strings. |
Options.ExportCellMargings: Boolean; | When true, the margins of the cell are exported |
Options.ExportCellProperties: Boolean; | When true, cell properties such as color, font, alignment are exported |
Options.ExportCellSizes: Boolean; | When true, the size of the cells is exported |
Options.ExportFormulas: Boolean; | When true, the formula is exported, otherwise the formula result is exported |
Options.ExportHardBorders: Boolean; | When true, cell borders are exported as hard borders for the Excel sheet |
Options.ExportHiddenColumns: Boolean; | When true, hidden columns are also exported |
Options.ExportHTMLTags: Boolean; | When true, HTML tags are also exported, otherwise all HTML tags are stripped during export |
Options.ExportImages: Boolean; | When true, images in the grid are also exported |
Options.ExportOverwrite: Boolean; | Controls if existing files should be overwritten or not during export |
Options.ExportOverwriteMessage: Boolean; | Sets the message to show warning to overwrite existing files during export |
Options.ExportPrintOptions: Boolean; | When true, the print options are exported to the XLS file |
Options.ExportShowGridLines: Boolean; | When true, grid line setting as set in TAdvStringGrid is exported to the XLS sheet |
Options.ExportShowInExcel: Boolean; | When true, the exported file is automatically shown in the default installed spreadsheet after export. |
Options.ExportSummaryRowBelowDetail: Boolean; | When true, summary rows are shown below detail rows in the exported XLS sheet |
Options.ExportWordWrapped: Boolean; | When true, cells are exported as wordwrapped cells |
Options.ImportCellFormats: Boolean; | When true, cells are imported with formatting as applied in the XLS sheet |
Options.ImportCellProperties: Boolean; | When true, cell properties such as color, font, alignment are imported |
Options.ImportCellSizes: Boolean; | When true, the size of cells is imported |
Options.ImportClearCells: Boolean; | When true, it will clear all existing cells in the grid before the import is done |
Options.ImportFormulas: Boolean; | When true, the formula is imported, otherwise only a formula result is imported |
Options.ImportImages: Boolean; | When true, images from the XLS sheet are imported |
Options.ImportLockedCellsAsReadOnly: Boolean; | When true, cells that are locked in the XLS sheet will be imported as read-only cells |
Options.ImportPrintOptions: Boolean; | When true, print settings as defined in the XLS sheet will be imported as grid.PrintSettings |
Options.UseExcelStandardColorPalette: Boolean; | When true, colors will be mapped using the standard Excel color palette, otherwise a custom palette will be included in the XLS sheet. |
TimeFormat: string; | Sets the format of cells with a time. When no format is specified, the default system time format is applied. |
XlsStartCol, XlsStartRow: integer; | Sets the top/left cell from where the import/export should start |
Advanced Topics on Importing & Exporting
In TTMSFNCDataGrid
, you can use the OnLoadCellData
and OnSaveCellData
events to apply transformations to cell data. Here’s how you can modify the approach to use these events instead of inheriting from TTMSFNCDataGrid
:
-
Assign Event Handlers: Define event handler methods for
OnLoadCellData
andOnSaveCellData
to apply your transformations (e.g., encryption and decryption). -
Attach Event Handlers: Assign these methods to the corresponding events of the
TTMSFNCDataGrid
component.
Here is a code example demonstrating how to use these events:
procedure TForm1.FormCreate(Sender: TObject);
begin
// Assign event handlers to the grid
Grid.OnSaveCellData := SaveCellDataHandler;
Grid.OnLoadCellData := LoadCellDataHandler;
end;
procedure TForm1.SaveCellDataHandler(Sender: TObject; AColumn, ARow: Integer; var AValue: TTMSFNCDataGridCellValue);
begin
// Apply encryption or any other transformation before saving
AValue := Encrypt(AValue);
end;
procedure TForm1.LoadCellDataHandler(Sender: TObject; AColumn, ARow: Integer; var AValue: TTMSFNCDataGridCellValue);
begin
// Apply decryption or reverse the transformation after loading
AValue := Decrypt(AValue);
end;
// Replace Encrypt and Decrypt with your actual transformation methods
function TForm1.Encrypt(const AValue: TTMSFNCDataGridCellValue): TTMSFNCDataGridCellValue;
begin
// Example encryption logic
Result := 'Encrypted_' + Grid.ValueToString(AValue);
end;
function TForm1.Decrypt(const AValue: TTMSFNCDataGridCellValue): TTMSFNCDataGridCellValue;
begin
// Example decryption logic
Result := StringReplace(Grid.ValueToString(AValue), 'Encrypted_', '', [rfReplaceAll]);
end;
In this example:
- SaveCellDataHandler
is called when saving cell data, applying an encryption transformation.
- LoadCellDataHandler
is called when loading cell data, applying a decryption transformation.
- Encrypt
and Decrypt
are placeholder methods for your actual transformation logic.
Make sure to replace the Encrypt
and Decrypt
functions with your real encryption and decryption implementations.
Sorting
To perform sorting in TTMSFNCDataGrid
, you typically use the Sort
method, which sorts based on column index and direction (ascending or descending). Sorting can be triggered programmatically or through user interaction with the grid, such as clicking on a column header.
Example of Sorting by Column
Here's a basic example of sorting a grid based on a column's data:
In the above code, the Sort
method is called with two parameters:
- The first parameter is the column index (0
in this case, meaning the first column).
- The second parameter is the sorting direction, which can be either gsdAscending
, gsdDescending
or gsdNone
.
In this picture you find an example of sorting:
Example: Dynamic Sorting Based on Column Click
In this example:
- You enable the Sorting function by setting it on true
- The Grid checks the current sort direction of the clicked column.
- If the column is already sorted in descending order, it sorts the column in ascending order. Otherwise, it sorts the column in descending order.
Advanced Sorting with Multiple Columns
You can also perform multi-column sorting, where sorting occurs based on multiple columns sequentially.
var
Columns: TArray<Integer>;
Directions: TArray<TTMSFNCDataGridSortDirection>;
begin
// Define columns to sort by
Columns := TArray<Integer>.Create(0, 1); // Sort by first and second columns
// Define corresponding sort directions
Directions := TArray<TTMSFNCDataGridSortDirection>.Create(sdDescending, sdAscending);
// Perform multi-column sorting
Grid.Sort(Columns, Directions);
end;
In this example:
- You specify the columns (0
and 1
, representing the first and second columns).
- You define sort directions for each column (Descending for the first column and ascending for the second column).
- Then, you use the Sort
method to sort based on both columns.
Using Custom Sorting Logic
For more complex sorting requirements, you can implement custom sorting by utilizing the OnCustomCompare
event, which allows you to define your own logic for comparing values in two cells.
procedure TForm1.GridCustomCompare(Sender: TObject; ACol, ARow1, ARow2: Integer; var AResult: Integer);
begin
// Custom comparison logic for sorting
if Grid.Floats[ACol, ARow1] > Grid.Floats[ACol, ARow2] then
AResult := 1
else if Grid.Floats[ACol, ARow1] < Grid.Floats[ACol, ARow2] then
AResult := -1
else
AResult := 0;
end;
In this example:
- The OnCustomCompare
event is assigned to the grid.
- You implement custom logic for comparing two rows based on the value of a specific column.
This is how sorting can be implemented using the style provided in your documentation. You can adjust the sorting logic based on your specific needs, such as custom comparison or sorting multiple columns.
Grouping
Grouping allows you to organize data within the TTMSFNCDataGrid
based on one or more columns. This feature makes it easier to analyze datasets by visually categorizing and displaying related data together. The grid also supports various aggregation methods, such as calculating the sum, average, or count for grouped data, making it a powerful tool for data analysis.
Enabling Grouping
To enable grouping, use the Group
method to specify the columns that should be grouped. For instance, to group by a specific column, you can call:
You can also group by multiple columns, allowing for hierarchical grouping:
Multi-Column Grouping with Custom Logic
For more advanced use cases, you can apply custom grouping logic when grouping by multiple columns. Here's an example of multi-column grouping with a custom grouping function:
Key Concepts in Multi-Column Grouping
Grouping in TTMSFNCDataGrid
works by categorizing rows based on the values of specific columns. When multi-column grouping is enabled, the grid groups data by the first column, then subgroups by the second column, and so on. You can also implement custom logic to define how grouping works.
Key Methods and Events:
Group(AColumns: TArray<Integer>)
: This method enables grouping by an array of columns.OnGetCustomGroup
: This event allows you to define custom grouping logic for each group level.
Example Scenario: Grouping Employee Data
In this example, we have an employee dataset with the following columns:
- Department
- Location
- Position
- Salary
We will group the data first by Location, then by Salary. Additionally, we'll implement custom logic to group Salaries into salary ranges instead of exact values.
Step 1: Setting Up the Grid with Employee Data
The first step is to initialize the grid, define the columns, and populate it with employee data. You will have columns like Department, Location, Position, and Salary, with corresponding rows representing different employees.
procedure TForm1.SetupGrid;
begin
// Define the columns
Grid.ColumnCount := 4;
Grid.Columns[0].Header := 'Department';
Grid.Columns[1].Header := 'Location';
Grid.Columns[2].Header := 'Position';
Grid.Columns[3].Header := 'Salary';
// Add some employee data
Grid.RowCount := 8;
Grid.Cells[0, 1] := 'HR'; Grid.Cells[1, 1] := 'New York'; Grid.Cells[2, 1] := 'Assistant'; Grid.Cells[3, 1] := '60000';
Grid.Cells[0, 2] := 'HR'; Grid.Cells[1, 2] := 'San Francisco'; Grid.Cells[2, 2] := 'Manager'; Grid.Cells[3, 2] := '95000';
Grid.Cells[0, 3] := 'IT'; Grid.Cells[1, 3] := 'New York'; Grid.Cells[2, 3] := 'Developer'; Grid.Cells[3, 3] := '85000';
Grid.Cells[0, 4] := 'IT'; Grid.Cells[1, 4] := 'Chicago'; Grid.Cells[2, 4] := 'Developer'; Grid.Cells[3, 4] := '80000';
Grid.Cells[0, 5] := 'Finance'; Grid.Cells[1, 5] := 'New York'; Grid.Cells[2, 5] := 'Analyst'; Grid.Cells[3, 5] := '70000';
Grid.Cells[0, 6] := 'Finance'; Grid.Cells[1, 6] := 'Chicago'; Grid.Cells[2, 6] := 'Analyst'; Grid.Cells[3, 6] := '72000';
Grid.Cells[0, 7] := 'Finance'; Grid.Cells[1, 7] := 'San Francisco'; Grid.Cells[2, 7] := 'Manager'; Grid.Cells[3, 7] := '95000';
end;
Step 2: Group by Multiple Columns
To group the data by Location, and Salary, you need to call the Group
method and pass an array of column indices (e.g., [1, 3]
for the 2 columns). This method will group the data hierarchically, starting with Location, and then Salary.
procedure TForm1.GroupData;
begin
// Group by Location (col 1), and Salary (col 3)
Grid.Group([1, 3]);
end;
Step 3: Implement Custom Grouping Logic
Grouping the Salary column can be done with a custom logic to categorize salaries into ranges like "$60,000-$70,000" instead of exact numbers. This can be achieved using the OnGetCustomGroup
event, where you define how each salary value is transformed into a salary range.
procedure TForm1.GridGetCustomGroup(Sender: TObject; ACell: TTMSFNCDataGridCellCoord; AData: TTMSFNCDataGridCellValue; ALevel: Integer; var AGroup: string);
var
Salary: Double;
begin
if ACell.Column = 3 then // If it's the salary column
begin
Salary := AData.ToFloat;
if Salary < 70000 then
AGroup := '$60,000 - $70,000'
else if Salary < 80000 then
AGroup := '$70,000 - $80,000'
else if Salary < 90000 then
AGroup := '$80,000 - $90,000'
else
AGroup := 'Above $90,000';
end;
end;
Step 4: Applying Grouping and Custom Logic
Once your custom logic is in place, you can apply it when performing the grouping. For instance, after grouping by the primary columns (Location, Salary), the grid will categorize the data further by salary ranges according to your custom rules.
This will result in a hierarchical data structure, where employees are first grouped by their department, then their location, and finally by their position and salary range.
Group Calculations
The TTMSFNCDataGrid
provides built-in methods to perform calculations on grouped data, such as sum, average, and distinct counts. You can also merge and add a summary from the group. For example, to calculate the sum of a grouped column:
Grid.Group(1); // Groups the data based on the second column (index 1).
Grid.GroupSum(6); // Calculates and displays the sum of the values in the seventh column (index 6) for each group.
Grid.GroupAverage(5); // Calculates and displays the average of the values in the sixth column (index 5) for each group.
Other calculation options include:
GroupAverage
: Calculate the average value within a groupGroupMax
: Find the maximum value in a groupGroupMin
: Find the minimum value in a groupGroupDistinct
: Count distinct values in a group
The calculation is a one-time operation. If you want to store calculations, check the Calculations chapter.
Group Sorting
You can also sort grouped data using the GroupSort
method. This method lets you specify the direction of sorting for each column:
To sort by multiple columns:
DataGrid.GroupSort([0, 1], [gsdAscending, gsdDescending]); // Sort first column ascending and second column descending order within the group
Ungrouping
To ungroup the data and return the grid to its original state, call the Ungroup
method this can also be done by adding a button:
Extra grouping features
Some extra capabilities for more visually appealing grouping can be set through the property grid.Options.Grouping. Through this property it can be enabled that group headers are automatically set in a different color and that cells from a group header are automatically merged. In addition, a group can also have a summary line. A summary line is an extra row below items that belong to the same group. This summary line can be used to put calculated group values in. The color for this summary line can also be automatically set as well as cell merging performed on this. See the grid.Options.Grouping description for all details.
Example
In this example of Grouping there are also Group Calculations, GroupAverage in column 'Cyl' and the sum in column 'Kw'
Filtering
The TTMSFNCDataGrid
allows you to filter data, enabling users to display only the rows that match specific criteria. This is particularly useful when working with large datasets, where you want to focus on a subset of the data.
Enabling Filtering
You can enable filtering on the grid by using the ApplyFilter
method. To define a filter condition, use the Filter
property and set conditions based on specific columns:
var
fltr: TTMSFNCDataGridDataFilterData;
begin
// Clear any existing filters
Grid.Filter.Clear;
// Add the filter condition (Column 1, value starts with 'A')
fltr := Grid.Filter.Add;
fltr.Column := 1; // First column (0-based index)
fltr.Condition := 'A*'; // Condition: values starting with 'A'
// Apply the filters
Grid.ApplyFilter;
end;
You can apply multiple filters:
var
fltr: TTMSFNCDataGridDataFilterData;
begin
Grid.Filter.Clear;
// Add the first filter condition (Column 1, value starts with 'A')
fltr := Grid.Filter.Add;
fltr.Column := 1; // First column (0-based index)
fltr.Condition := 'A*'; // Condition: values starting with 'A'
// Add the second filter condition (Column 3, value = 40)
fltr := Grid.Filter.Add;
fltr.Column := 3; // Fourth column (0-based index)
fltr.Condition := '=40'; // Condition: values equal to 40
// Apply the filters
Grid.ApplyFilter;
end;
Custom Filter Options
The grid allows you to customize filter options using different operators, such as:
gftStartsWith
: Checks if the cell starts with a particular substring.gftEndsWith
: Checks if the value ends with a particular substring.gftContains
: Checks if the cell contains a particular substring.gftNotContains
: Checks if the cell does not contain a particular substring.gftEqual
: Checks if the value equals the specified condition.gftEmpty
: Checks if the value is empty.gftNotEmpty
: Checks if the value is not empty.gftNotEqual
: Checks if the value does not equal the specified condition.gftLargerThan
: Filters values greater than the specified value.gftSmallerThan
: Filters values less than the specified value.gftLargerOrEqualThan
: Filters values greater or equal than the specified value.gftSmallerOrEqualThan
: Filters values smaller or equal than the specified value.
To apply this, set the public FilterType property while setting up the filter;
var
fltr: TTMSFNCDataGridDataFilterData;
begin
fltr := Grid.Filter.Add;
fltr.FilterType := gftLargerThan;
fltr.Column := 0;
fltr.Condition := '40';
Grid.ApplyFilter;
//Results in a condition = "> 40"
end
Clearing Filters
To clear any applied filters and display all rows again, use the ClearFilter
method:
Filter Row
The filter row is a feature that can be used to apply filtering in the grid. If you already have data in the grid, you might need to start off by inserting a new row, making sure the filter editors are not covering potential data that needs to be taken into account when filtering. Typically, the filter row is part of the fixed rows. If you have a fixed row containing headers, it might be useful to add another fixed row.
Enabling the filter row on top of the filter drop-down (available by default) is easy. We enable filtering first, then specify which kinds of filter options we want for runtime filtering and then specify which row needs to be allocated to show the filter options.
Grid.Options.Filtering.Enabled := True;
Grid.Options.Filtering.Controls := [gfcButton, gfcEditor];
Grid.Options.Filtering.Row := 1;
By default, enabling a filter row automatically detects which kind of editor is required. This can be customized at column level by using the following code.
Grid.ColumnByHeader('Joined').AddSetting(gcsFilterEditorType);
Grid.ColumnByHeader('Joined').FilterEditorType := gfetDateTime;
The following types are available
gfetAutomatic
: Automatically detects the value type and chooses one of the other types.gfetString
: A standard edit for string based valuesgfetBoolean
: A checkbox for boolean based valuesgfetDateTime
: A date/time picker for TDateTime based valuesgfetFloat
: A spinbox for float valuesgfetNumber
: A spinbox for number valuesgfetCustom
: Specify your own editor
Additionally, when the column width is sufficiently large, a filter type selector and a clear button will appear.
Custom Filter Editor
When you are in need for a custom filter editor, you can select the filter type gfetCustom, which enables you to create your own editor via the OnCreateCustomFilterEditor event. Below is a sample to create a combobox which filters the progress column via a selection of ranges.
Grid.BeginUpdate;
Grid.RemoveFilterEditor(MakeCell(Grid.ColumnIndexByHeader('Progress'), 1));
Grid.Columns[Grid.ColumnIndexByHeader('Progress')].FilterEditorType := gfetCustom;
Grid.Columns[Grid.ColumnIndexByHeader('Progress')].AddSetting(gcsFilterEditorType);
Grid.EndUpdate;
When we implement the OnCreateCustomFilterEditor you can create an instance of the control of your choice, set content and bind events for filtering purposes
function TForm1.GridCreateCustomFilterEditor(Sender: TObject;
ACell: TTMSFNCDataGridCellCoord): TTMSFNCDataGridCellControl;
var
cbo: TComboBox;
begin
Result := TComboBox.Create(nil);
cbo := TComboBox(Result);
cbo.Items.Add('');
cbo.Items.Add('<= 25');
cbo.Items.Add('> 25 & <= 50');
cbo.Items.Add('> 50 & <= 75');
cbo.Items.Add('> 75');
cbo.OnChange := DoComboChange;
end;
procedure TForm1.DoComboChange(Sender: TObject);
var
cbo: TComboBox;
f: TTMSFNCDataGridDataFilterData;
begin
cbo := TComboBox(Sender);
Grid.RemoveFilter;
f := Grid.Filter.ColumnFilter[Grid.ColumnIndexByHeader('Progress')];
f.Condition := cbo.Text;
Grid.ApplyFilter;
end;
Chaining Filters
With the filter row as an option on top of the already built-in filtering features there are plenty of ways to browse through the data. If visual filtering is not applicable to your application, programmatic filtering can be an option and in this area we provide a way to chain filter operations together. Let's take the following example, where we find if the Name contains 'k', the Status equals 'Abroad' and the Progress is smaller than 50.
Grid.ClearFilter;
Grid.Filter.Add(Grid.ColumnIndexByHeader('Name'), gftContains, 'k')
.&And(Grid.ColumnIndexByHeader('Status'), gftEqual, 'Abroad')
.&And(Grid.ColumnIndexByHeader('Progress'), gftSmallerThan, '50');
Grid.ApplyFilter;
HTML formatted text, cell anchors, highlighting and marking in cells
The grid supports HTML formatted strings in cells. This is based on a small & fast HTML rendering engine. This engine implements a subset of the HTML standard to display formatted text. It supports following tags :
B : Bold tag
Example : This is a test
U : Underline tag
Example : This is a testI : Italic tag
Example : This is a testS : Strikeout tag
Example : This is aA : anchor tag
<A href="value"> : text after tag is an anchor. The 'value' after the href identifier is the anchor. This can be an URL (with ftp,http,mailto,file identifier) or any text.
If the value is an URL, the shellexecute function is called, otherwise, the anchor value can be found in the OnAnchorClick event </A> : end of anchor
Examples : This is a test This is a test This is a test
FONT : font specifier tag
<FONT face='facevalue' size='sizevalue' color='colorvalue' bgcolor='colorvalue'> : specifies font of text after tag.with
Examples : This is a test This is a test
HR : horizontal line
<HR>
: inserts linebreak with horizontal line
BR : linebreak
<BR>
: inserts a linebreak
BODY : body color / background specifier
<BODY bgcolor="colorvalue" [bgcolorto="colorvalue"] [dir="v|h"] background="imagefile
specifier"> : sets the background color of the HTML text or the background bitmap file
Example :
<BODY bgcolor="gcYellow"> : sets background color to yellow
<BODY background="file://c:\test.bmp"> : sets tiled background to file test.bmp
<BODY bgcolor="gcYellow" bgcolorto="gcWhite" dir="v"> : sets a vertical gradient from yellow to white
IND : indent tag This is not part of the standard HTML tags but can be used to easily create multicolumn text
Example : This will beIMG : image tag
<IMG src="specifier:name" [align="specifier"] [width="width"] [height="height"]
[alt="specifier:name"] > : inserts an image at the location
specifier can be: name of image in a BitmapContainer
Optionally, an alignment tag can be included. If no alignment is included, the text alignment with respect to the image is bottom. Other possibilities are: align="top" and align="middle"
The width & height to render the image can be specified as well. If the image is embedded in anchor tags, a different image can be displayed when the mouse is in the image area through the Alt attribute.
Examples :
This is an image <IMG src="name">
SUB : subscript tag
Example : This is 9/16 looks like 9/16SUP : superscript tag
UL : list tag
Example :- By default, memo fields are displayed as
(MEMO)
in the grid, similar to how it works in the default TGrid or TStringGrid in FMX and VCL. - To show the actual content of memo fields, set the global property
ShowMemoFields = true
. - To automatically adjust the row sizes based on the text in memo fields, call the following method after activating the dataset:
- A database field of type
ftBoolean
is displayed astrue
orfalse
by default. - To display Boolean fields as checkboxes, set
ShowBooleanFields = true
. - Additionally, the adapter can show checkboxes for fields that are not of type
ftBoolean
, but contain two values (e.g.,1
for true and0
for false). This is useful for databases that don't natively support Boolean fields. - To display checkboxes for such fields, configure the following properties:
- By default, image blobs are displayed as
(GRAPHIC)
. - To display actual images (BMP, GIF, JPEG) stored in
BLOB
fields, setShowPictureFields = true
. - If the field type is
ftBlob
(notftGraphic
), and the BLOB contains image data, you can manually set the column to display images by configuring: - To set an HTML template, use the property
Adapter.Columns[Index].HTMLTemplate
. - The template is a string where DB field references like
<#DBFIELDNAME>
will be replaced by the actual field values for each record. - The database table is editable
- The database field is editable
- Master Table: Contains parent records (e.g., `Orders`).
- Detail Table: Contains child records linked to the master table (e.g., `OrderDetails` with a foreign key `OrderID`).
- Create Datasets
- Create datasets for the master (`Orders`) and detail (`OrderDetails`) tables.
- Use `TDataSource` components to link the datasets (`dsMaster` and `dsDetail`).
- Configure Database Adapters
- Place two `TTMSFNCDataGridDatabaseAdapter` components on the form.
- Set the `DataSource` of `MasterAdapter` to `dsMaster` and `DetailAdapter` to `dsDetail`.
- Master Grid Setup
- Drop a `TTMSFNCDataGrid` component on the form and set it to display fields from the master dataset (`Orders`).
- Bind this grid to `MasterAdapter`.
- Detail Grid Setup
- Add another `TTMSFNCDataGrid` for the detail dataset (`OrderDetails`).
- Bind this grid to `DetailAdapter`.
- Define Master-Detail Relationship
- Set the `MasterSource` property of the detail dataset (`dsDetail`) to the master dataset’s `TDataSource`.
- Define the `MasterFields` to specify the linking key (e.g., `OrderID`).
- Display Detail Data:
- Set the DetailControl property of the `MasterAdapter` to `OrderDetails` Grid.
<LI>List item 1
<LI>List item 2
<UL>
<LI> Sub list item A
<LI> Sub list item B
</UL>
<LI>List item 3
</UL>
LI : list item
<LI [type="specifier"] [color="color"] [name="imagename"]>
: new list item specifier can be
"square", "circle" or "image" bullet. Color sets the color of the square or circle bullet. Imagename
sets the PictureContainer image name for image to use as bullet
SHAD : text with shadow
Z : hidden textSpecial characters Following standard HTML special characters are supported : < : less than : < > : greater than : > & : & " : " : non breaking space ™ : trademark symbol € : euro symbol § : section symbol © : copyright symbol ¶ : paragraph symbol
When hyperlinks are specified in grid cells, these hyperlinks are displayed underlined and in blue color. When the hyperlink is clicked, the OnCellAnchorClick event is triggered. Via HTML formatting, the grid also offers highlighting or marking of text in grid cells. This can be used to indicate text that matches a search or to show errors.
Data Binding
The TTMSFNCDataGrid
supports data binding, allowing you to easily link the grid to various data sources, such as databases, arrays, or custom collections. This feature simplifies the process of displaying, editing, and managing large datasets within the grid.
Setting Up Data Binding
To bind the grid to a dataset, you need to set the DataAdapter
property. This property connects the TTMSFNCDataGrid
to a specific data source. For example, to bind to a dataset, you can use:
The TTMSFNCDataGrid
uses adapters to communicate with different data sources. These adapters handle the interaction between the grid and your data, automatically populating the grid with records and reflecting changes made in the dataset.
Using Database Adapters
When working with databases, use the TTMSFNCDataGridDatabaseAdapter
to bind the grid to a database source. For example, to bind the grid to a TDataSet
, you would use:
var
Adapter: TTMSFNCDataGridDatabaseAdapter;
begin
Adapter := TTMSFNCDataGridDatabaseAdapter.Create(Self);
Adapter.DataSource := MyDataSource; // Link to the dataset
DataGrid.Adapter := Adapter; // Bind the adapter to the grid
end;
Memo Fields, Boolean Fields & Image Blobs
The TTMSFNCDataGridDatabaseAdapter can handle various data types and display them in a grid, such as memo fields, Boolean fields, and image blobs.
Memo Fields
Boolean Fields
Adapter.Columns[columnindex].CheckBoxField = true;
Grid.Columns[columnindex].Binding.BooleanTrueValue = <true_value>;
Grid.Columns[columnindex].Binding.BooleanFalseValue = <false_value>;
Image Blobs
HTML Templates
HTML templates allow you to customize how multiple fields are displayed in a single cell, including optional HTML formatting.
Suppose a table has a field called Length (cm)
. You can format a cell with blue text and bold formatting using the following HTML template:
This would result in a grid cell that looks like this:
Editing
The adapter supports various inplace editors as well as the capability to use external controls as inplace editor for the grid. The “Editing” chapter in this document has an overview of all possible inplace editors that are included and how to use external editors as well. To enable editing in the grid, it is required that
When a selected cell is clicked, the inplace editing starts. It is important to know that editing of a cell or row stops when the inplace editor loses focus. Only when it loses focus, the edited value is internally stored to post when the row changes.
Master-Detail
Master-Detail relationships using TTMSFNCDataGrid and TTMSFNCDataGridDatabaseAdapter allow developers to create intuitive and synchronized data representations, where a master grid shows parent records, and a detail grid reflects the corresponding child records based on the selected master entry. By linking the master and detail grids through the adapter, the detail grid can dynamically refresh and display the appropriate records from the child table. This is achieved by setting up datasets for both tables and using TDataSource components for database linking.
1. Setting up Master-Detail Tables
The master-detail relationship consists of:
2. Configuring Database Components
3. Linking Master and Detail Grids
The DetailControl property of the Database adapter is capable of hosting any type of control in a Master-Detail relationship.