1

I am creating TTeeGrid (TDataSet descendant) at runtime supplied by API. I noticed that as the number of columns increases, the performance decreases. Meaning, the time of creating TTeeGrid is getting slower.

I am developing firemonkey app here and the performance is noticeable in iOS and Android when it reach to 20 columns or more.

Here's my code:

procedure TformMain.btnCreateTeeGridClick(Sender: TObject);
begin
   FreeAndNil(CanvassGrid); // delete the old grid

   // create a new grid
   CanvassGrid := TTeeGrid.Create(recCanvass);
    With CanvassGrid do
    begin
      Parent := recCanvass;
      Align := TAlignLayout.Client;
      Margins.Top := 5;
      Margins.Left := 5;
      Margins.Right := 5;
      Margins.Bottom := 5;
      ScrollBars.Visible := True;
      Header.Format.Font.Size := 11;
      Cells.Format.Font.Size := 11;
      TabOrder := 0;
      ScrollBars.Visible := False;
    end;
end;

Is there a way that I can improve the performance or did I missed something in my code that causes the performance to slow?


UPDATE 1: Minimal Reproducible Example

FMX File

object Form9: TForm9
  Left = 0
  Top = 0
  Caption = 'MRE TeeGrid Runtime'#13#10
  ClientHeight = 480
  ClientWidth = 294
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  DesignerMasterStyle = 0
  object btn1: TButton
    Align = Bottom
    Position.Y = 440.000000000000000000
    Size.Width = 294.000000000000000000
    Size.Height = 40.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 9
    Text = 'CREATE TEEGRID'
    OnClick = btn1Click
  end
  object aniSearchProcess: TAniIndicator
    Position.X = 128.000000000000000000
    Position.Y = 216.000000000000000000
  end
  object lyt1: TLayout
    Align = Client
    Size.Width = 294.000000000000000000
    Size.Height = 440.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 11
  end
  object cur1: TFDGUIxWaitCursor
    Provider = 'FMX'
    Left = 32
    Top = 32
  end
  object dvr1: TFDPhysSQLiteDriverLink
    Left = 88
    Top = 32
  end
  object con1: TFDConnection
    Params.Strings = (
      'DriverID=SQLite')
    Connected = True
    LoginPrompt = False
    Left = 144
    Top = 32
  end
  object loc1: TFDLocalSQL
    Connection = con1
    Active = True
    Left = 200
    Top = 32
  end
  object rsc1: TRESTClient
    Accept = 'application/json, text/plain; q=0.9, text/html;q=0.8,'
    AcceptCharset = 'utf-8, *;q=0.8'
    BaseURL = 
      'https://me6hwinr2k.execute-api.ap-southeast-1.amazonaws.com/v0/d' +
      'bqueries?item-var=9&qty=25'
    Params = <>
    Left = 32
    Top = 112
  end
  object rsq1: TRESTRequest
    Client = rsc1
    Params = <>
    Response = rsp1
    SynchronizedEvents = False
    Left = 32
    Top = 176
  end
  object rsp1: TRESTResponse
    ContentType = 'application/json'
    Left = 32
    Top = 240
  end
  object rsd1: TRESTResponseDataSetAdapter
    Active = True
    Dataset = mtb1
    FieldDefs = <>
    Response = rsp1
    Left = 32
    Top = 304
  end
  object mtb1: TFDMemTable
    Active = True
    FieldDefs = <
      item
        Name = 'Category'
        DataType = ftWideString
        Size = 255
      end
      item
        Name = 'ID'
        DataType = ftWideString
        Size = 255
      end
      item
        Name = 'Item'
        DataType = ftWideString
        Size = 255
      end
      item
        Name = 'Qty'
        DataType = ftWideString
        Size = 255
      end
      item
        Name = 'Container'
        DataType = ftWideString
        Size = 255
      end
      item
        Name = 'Size'
        DataType = ftWideString
        Size = 255
      end
      item
        Name = 'Ex temporibus dolore consequatur.'
        DataType = ftWideString
        Size = 255
      end
      item
        Name = 'Et cum aut est nostrum...'
        DataType = ftWideString
        Size = 255
      end
      item
        Name = 'Sequi quibusdam eum.'
        DataType = ftWideString
        Size = 255
      end>
    IndexDefs = <>
    FetchOptions.AssignedValues = [evMode]
    FetchOptions.Mode = fmAll
    ResourceOptions.AssignedValues = [rvSilentMode]
    ResourceOptions.SilentMode = True
    UpdateOptions.AssignedValues = [uvCheckRequired, uvAutoCommitUpdates]
    UpdateOptions.CheckRequired = False
    UpdateOptions.AutoCommitUpdates = True
    StoreDefs = True
    Left = 32
    Top = 368
  end
end

FMX Procedures

unit Main;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FireDAC.UI.Intf, FireDAC.FMXUI.Wait, FireDAC.Stan.ExprFuncs,
  FireDAC.Phys.SQLiteDef, FireDAC.Stan.Intf, FireDAC.Stan.Option,
  FireDAC.Stan.Error, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool,
  FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.SQLite, Data.DB,
  FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, REST.Types,
  FMX.Controls.Presentation, FMX.StdCtrls, FireDAC.Comp.DataSet,
  FireDAC.Comp.Client, REST.Response.Adapter, REST.Client, Data.Bind.Components,
  Data.Bind.ObjectScope, FireDAC.Phys.SQLiteVDataSet, FireDAC.Comp.UI,
  FMXTee.Control, FMXTee.Grid, FMX.Layouts;

type
  TForm9 = class(TForm)
    cur1: TFDGUIxWaitCursor;
    dvr1: TFDPhysSQLiteDriverLink;
    con1: TFDConnection;
    loc1: TFDLocalSQL;
    rsc1: TRESTClient;
    rsq1: TRESTRequest;
    rsp1: TRESTResponse;
    rsd1: TRESTResponseDataSetAdapter;
    mtb1: TFDMemTable;
    btn1: TButton;
    aniSearchProcess: TAniIndicator;
    lyt1: TLayout;
    procedure btn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form9: TForm9;
  tgd1: TTeeGrid;

implementation

{$R *.fmx}

procedure TForm9.btn1Click(Sender: TObject);
var
  i, CanvassItemId, e : Integer;
begin
  aniSearchProcess.Visible := True;
  aniSearchProcess.Enabled := True;
  {$IFDEF MSWINDOWS}
    Application.ProcessMessages;
  {$ENDIF}
  {$IF DEFINED(iOS) or DEFINED(ANDROID)}
    Application.HandleMessage;
  {$ENDIF}

  FreeAndNil(tgd1); //free old grid

  //create new grid
  tgd1 := TTeeGrid.Create(lyt1);
  With tgd1 do
  begin
    Parent := lyt1;
    Align := TAlignLayout.Client;
    Margins.Top := 5;
    Margins.Left := 5;
    Margins.Right := 5;
    Margins.Bottom := 5;
    ScrollBars.Visible := True;
    Header.Format.Font.Size := 11;
    Cells.Format.Font.Size := 11;
    TabOrder := 0;
    ScrollBars.Visible := False;
  end;

  con1.StartTransaction;
  try
    //define the API here for duplicate/update, initial click and subsequent clicks
    rsc1.BaseURL := ...;
    rsq1.Execute;
    rsd1.Active := True;
    mtb1.Active;
    tgd1.DataSource := mtb1;
    tgd1.Enabled := True;

    // adjust the column properties dynamically
    with tgd1 do
    begin
      for i := 0 to Columns.Count -1 do
      begin
        if i = 0 then
        begin
          Columns[i].Visible := False; // category column
        end
        else if (i = 1) then
        begin
          Columns[i].Visible := False; // id column
        end
        else if (i = 2) then
        begin
          Columns[i].Width.Value := 120; // item column
        end
        else if (i = 3) then
        begin
          Columns[i].Width.Value := 30; // qty column
        end
        else if (i = 4) then
        begin
          Columns[i].Width.Value := 50; // container column
        end
        else if (i = 5) then
        begin
          Columns[i].Width.Value := 50; // size column
        end
        else
        begin
          Columns[i].Width.Value := 50; // subsequent random columns
        end;
      end;
    end;
  finally
    con1.Commit;
  end;

  aniSearchProcess.Visible := False;
  aniSearchProcess.Enabled := False;
  {$IFDEF MSWINDOWS}
    Application.ProcessMessages;
  {$ENDIF}
  {$IF DEFINED(iOS) or DEFINED(ANDROID)}
    Application.HandleMessage;
  {$ENDIF}

end;

end.
RickyBelmont
  • 619
  • 4
  • 11
  • 2
    Is this Steema's TeeGrid for VCL/FMX or something else? Regardless it is very unlikely any Grid style component is a descendant of TDataSet which is a non-visual data access component. More often a Grid has a property that allows it to be hooked up to a TDataSource which then references a TDataSet descendant. – Brian Aug 21 '20 at 20:11
  • So this is using LiveBindings, is it? Please provide an [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – MartynA Aug 21 '20 at 20:19
  • @MartynA I am not actually using LiveBindings here but direct connection to FDMemTable as source data and structure at runtime. I have provided the MRE as requested (see UPDATE 1 above). Please note that the sample API provided is limited for purpose of demonstration only. – RickyBelmont Aug 22 '20 at 01:06
  • Here when I run your example all the time is taken establishing the secure connection to get the content. As long as the connection hasn't timed out on the current run additional presses of the the button have the grid is created quickly. Might help some with larger column counts to surround the column setup with `try columns.beginupdate; ` and `finally columns.endupdate;` – Brian Aug 24 '20 at 19:14
  • @Brian Thanks for this advise. I tried your suggestion and it improves somehow but it again it starts to slow down when I reached like 35 columns or more. I suspect that it is the overhead data of the columns that makes it slower as the columns increase. – RickyBelmont Aug 25 '20 at 01:07
  • It hangs up already after 35 columns. By the way, this happens only when I ran it in iOS simulator which definitely could be the same case if I do it in actual devise iOS and Android. – RickyBelmont Aug 25 '20 at 01:09

0 Answers0