Blog

All Blog Posts  |  Next Post  |  Previous Post

Powerful and Intuitive Data Filtering for Delphi Developers in VCL, FMX and TMS WEB Core

Today

Efficient data filtering is crucial when working with large datasets. With TTMSFNCFilterDialog, you can seamlessly apply filters to various components, including TTMSFNCDataGrid. This blog explores how to integrate TTMSFNCFilterDialog with any control—using TTMSFNCDataGrid as an example—to enable dynamic filtering without manual data handling.


TMS Software Delphi  Components

The Advantages of TTMSFNCFilterDialog?

The TTMSFNCFilterDialog provides a visual and intuitive way to filter data, eliminating the need for users to manually construct filter conditions. By leveraging this component, you can:

  • Dynamically apply filters to any component.
  • Utilize a user-friendly filter dialog instead of manually setting filter conditions.
  • Integrate advanced filtering logic, including AND/OR group operations and data type-based filtering.
  • Customize the UI and language settings to fit your application’s needs.

This control is a more flexible version of TTMSFNCDataSetFilterDialog, allowing you to filter data beyond just database datasets. In this example, we will filter simple grid data.



Setting Up TTMSFNCFilterDialog with TTMSFNCDataGrid

Step 1: Creating Sample Grid Data

First, we populate a TTMSFNCDataGrid with different types of data. For this example, we will use sample data generated by the control.

procedure TSampleForm.FormCreate(Sender: TObject);
begin
  DataGrid.LoadSampleData;
  DataGrid.Columns[0].Formatting.&Type := gdftNumber;
  DataGrid.Columns[1].Formatting.&Type := gdftDefault; //Text
  DataGrid.Columns[2].Formatting.&Type := gdftDate;
  DataGrid.Columns[3].Formatting.&Type := gdftDefault; //Text
end;


Step 2: Setting Up the Filter Dialog

Next, we create an instance of TTMSFNCFilterDialog, configure it, and retrieve the different input columns using the OnGetFilterBuilderDataColumns event.

procedure TSampleForm.FormCreate(Sender: TObject);
begin
  DataGrid.LoadSampleData;
  DataGrid.Columns[0].Formatting.&Type := gdftNumber;
  //DataGrid.Columns[1] is Text
  DataGrid.Columns[2].Formatting.&Type := gdftDate;
  //DataGrid.Columns[3] is Text

  fd := TTMSFNCFilterDialog.Create(Self);
  fd.OnGetFilterBuilderDataColumns := DoGetFilterBuilderDataColumns;
end;
You can also use the SQL formatted filtering by setting the following property:

  fd.FilterBuilder.FormatType := fftDelphiDataSet;
  //Otherwise our own format type fftUniversalFilterExpressions is used.

Step 3: Mapping Filter Builder Columns

To optimize how columns are handled in the filter dialog, we map TTMSFNCDataGrid columns by assigning their names from the fixed row and their format type.

procedure TSampleForm.DoGetFilterBuilderDataColumns(Sender: TObject; AFilterBuilder: TTMSFNCFilterBuilder; ADataColumns: TTMSFNCFilterBuilderColumns);
var
  I: Integer;
  dt: TTMSFNCFilterBuilderDataType;
begin
  ADataColumns.Clear;
  for I := 0 to TMSFNCDataGrid1.Columns.Count - 1 do
  begin
    case DataGrid.Columns[I].Formatting.&Type of
      gdftDateTime: dt := fdtDateTime;
      gdftDate: dt := fdtDate;
      gdftTime: dt := fdtTime;
      gdftFloat: dt := fdtFloat;
      gdftNumber: dt := fdtNumber;
      gdftBoolean: dt := fdtBoolean;
      gdftDefault: dt := fdtText;
      else dt := fdtAutomatic;
    end;
    ADataColumns.AddColumn(TMSFNCDataGrid1.Strings[I,0], dt);
  end;
end;


Step 4: Applying Filters to the Data Grid

When a user applies a filter, we validate and apply it to the TTMSFNCDataGrid.

procedure TSampleForm.ValidateFilter;
var
  ia: TTMSFNCFilterValidateInputArray;
  I, J: Integer;
begin
  if DataGrid.ColumnCount = fd.FilterBuilder.DataColumns.Count then
  begin
    SetLength(ia, DataGrid.ColumnCount, DataGrid.RowCount - DataGrid.FixedRowCount);
    for I := 0 to DataGrid.ColumnCount - 1 do
    begin
      for J := 0 to DataGrid.RowCount - DataGrid.FixedRowCount -1 do
      begin
        ia[I,J] := DataGrid.Cells[I,J + DataGrid.FixedRowCount];
      end;
    end;
    oa := fd.FilterBuilder.ValidateFilterArray(ia);
    SetFilter;
  end;
  TMSFNCDataGrid1.Repaint;
end;
This function ValidateFilterArray processes an array of data and returns a dynamic array of Boolean values.
Alternatively, ValidateFilterRow can be used to evaluate a single row and return a Boolean indicating whether it matches the filter.

Step 5: Opening the Filter Dialog

To display the filter dialog and apply the filter:

procedure TSampleForm.FilterBtn(Sender: TObject);
begin
  fd.Execute;
  ValidateFilter;
end;

Step 6: Displaying the Filter Results

There are two ways to visualize the filter results: hiding non-matching rows or highlighting matching rows.

Option 1: Hiding Non-Matching Rows
procedure TSampleForm.SetFilter;
var
  I: Integer;
begin
  if (Length(oa) > 0) then
  begin
    for I := DataGrid.FixedRowCount to DataGrid.FixedRowCount + Length(oa) - 1 do
    begin
      if not oa[I - DataGrid.FixedRowCount] then
        DataGrid.HideRow(I)
      else
        DataGrid.UnhideRow(I);
    end;
  end
  else
    DataGrid.UnhideAllRows;
end;
TMS Software Delphi  Components

Option 2: Highlighting Matching Rows
procedure TSampleForm.DataGridBeforeDrawCell(Sender: TObject; AGraphics: TTMSFNCGraphics; ACell: TTMSFNCDataGridCell; var ACanDraw: Boolean);
begin
  if (ACell.Row >= DataGrid.FixedRowCount) and (Length(oa) > ACell.Row - DataGrid.FixedRowCount) then
  begin
    if oa[ACell.Row - DataGrid.FixedRowCount] then
      AGraphics.Fill.Color := gcDarkseagreen;
  end;
end;


TMS Software Delphi  Components


Here you can find the full source code.

Future Implementation in TMSFNCDataGrid

This filtering feature is highly useful and should not require custom implementation for every grid.
Therefore, TTMSFNCDataGrid will include built-in support for TTMSFNCFilterDialog in a future release.


Conclusion

The TTMSFNCFilterDialog provides a powerful yet easy-to-use solution for dynamic filtering in Delphi applications. As demonstrated with TTMSFNCDataGrid, it offers a seamless integration that enhances user experience by eliminating the need for complex filtering logic.



Gjalt Vanhouwaert




This blog post has received 2 comments.


1. Wednesday, February 26, 2025 at 2:32:02 PM

Can this be used with Aurelius if you use the Dataset?

Pelletier Martin


2. Wednesday, February 26, 2025 at 5:44:16 PM

A good example would be on an XData client, where we don''t always have all the records loaded, and we need to make a call the XData server according to the filter. Maybe in a future sample.

ghazali@ghazali.be




Add a new comment

You will receive a confirmation mail with a link to validate your comment, please use a valid email address.
All fields are required.



All Blog Posts  |  Next Post  |  Previous Post