Search Results for

    Show / Hide Table of Contents

    Advanced Reports from Lists (Delphi)

    Note

    This demo is available in your FlexCel installation at <FlexCel Install Folder>\Demo\Delphi\Modules\20.Reports\22b.Advanced Reports From Lists and also at https:​//​github.​com/​tmssoftware/​TMS-​FlexCel.​VCL-​demos/​tree/​master/​Delphi/​Modules/​20.​Reports/​22b.​Advanced Reports From Lists

    Overview

    Most of the demos here use datasets as datasources. This is just for convenience, so we share the same data layer in all demos, and also because the focus is in the Excel templates, not so much in the data layer. But you can use any TList<T> and TArray<T> as a datasource in a FlexCel report, and this is what we will show here.

    This demo shows some features not shown on the Reports From Lists example.

    Concepts

    • How to do a master-detail report when the details are nested many levels inside the master. In this case, the class Country has a People class, and the People class has a list of Language objects. If People was a TList<> inside Country and you wanted to use that list, you would just define a __People__ band (this is shown in the Reports From Lists example). But as the TList<> is inside People which in turn is inside Country, you need to define a __People.Language__ band.

    • How to reference a table with dots using [square brackets]. If you write in a cell <#tablename.section.field> FlexCel will interpret this as table "tablename", field "section.field". The text up to the first dot is always the table, and the rest is the field. But sometimes you might want this to being interpreted as table "tablename.section", field "field". To do so, you need to write <#[tablename.section].field>. In this particular case, we have a table "People.Language" which we defined in the previous point. If we wrote in cell B1: "<#people.language.speakers.percent> FlexCel would interpret this is the table "people", not "people.language" which is what we need. To make FlexCel understand that we want a table "people.language" we use <#[people.language].speakers.percent>

    Files

    DataModel.pas

    unit DataModel;
    
    interface
    uses Generics.Collections;
    
    type
    
      TArea = class
      strict private
        FWater: Int32;
        FLand: Int32;
        function Get_Total: Int32;
    
      public
        constructor Create(const aWater: Int32; const aLand: Int32);
        property Total: Int32 read Get_Total;
        property Water: Int32 read FWater;
        property Land: Int32 read FLand;
      end;
    
    
      TGeography = class
      strict private
        FArea: TArea;
      public
        constructor Create(const aArea: TArea);
        destructor Destroy; override;
        property Area: TArea read FArea;
      end;
    
      TLanguageSpeakers = class
      strict private
        FAbsoluteNumber: Int32;
        FPercent: double;
    
      public
        constructor Create(const aAbsoluteNumber: Int32; const aPercent: double);
        property AbsoluteNumber: Int32 read FAbsoluteNumber;
        property Percent: double read FPercent;
      end;
    
    
    
      TLanguageName = class
      strict private
        FShortName: string;
        FLongName: string;
      public
        constructor Create(const aShortName: string; const aLongName: string);
        property ShortName: string read FShortName;
        property LongName: string read FLongName;
      end;
    
      TLanguage = class
      strict private
        FName: TLanguageName;
        FSpeakers: TLanguageSpeakers;
    
      public
        constructor Create(const aName: TLanguageName; const aSpeakers: TLanguageSpeakers);
        destructor Destroy; override;
        property Name: TLanguageName read FName;
        property Speakers: TLanguageSpeakers read FSpeakers;
      end;
    
      TPeople = class
      strict private
        FPopulation: Int32;
        FLanguage: TObjectList<TLanguage>;
    
      public
        constructor Create(const aPopulation: Int32);
        destructor Destroy; override;
        property Population: Int32 read FPopulation;
        property Language: TObjectList<TLanguage> read FLanguage;
      end;
    
      TCountry = class
      strict private
        FName: string;
        FPeople: TPeople;
        FGeography: TGeography;
    
      public
        constructor Create(const aName: string; const aPeople: TPeople; const aGeography: TGeography);
        destructor Destroy; override;
        property Name: string read FName;
        property People: TPeople read FPeople;
        property Geography: TGeography read FGeography;
      end;
    
    
    
    implementation
    
    { TArea }
    
    constructor TArea.Create(const aWater, aLand: Int32);
    begin
      inherited Create;
      FWater := aWater;
      FLand := aLand;
    
    end;
    
    function TArea.Get_Total: Int32;
    begin
      Result := Water + Land;
    end;
    
    { TGeography }
    
    constructor TGeography.Create(const aArea: TArea);
    begin
      inherited Create;
      FArea := aArea;
    end;
    
    destructor TGeography.Destroy;
    begin
      FArea.Free;
      inherited;
    end;
    
    { TLanguageSpeakers }
    
    constructor TLanguageSpeakers.Create(const aAbsoluteNumber: Int32;
      const aPercent: double);
    begin
      inherited Create;
      FAbsoluteNumber := aabsoluteNumber;
      FPercent := aPercent / 100.0;
    end;
    
    { TLanguageName }
    
    constructor TLanguageName.Create(const aShortName, aLongName: string);
    begin
      inherited Create;
      FShortName := aShortName;
      FLongName := aLongName;
    end;
    
    { TLanguage }
    
    constructor TLanguage.Create(const aName: TLanguageName;
      const aSpeakers: TLanguageSpeakers);
    begin
      inherited Create;
      FName := aName;
      FSpeakers := aSpeakers;
    end;
    
    destructor TLanguage.Destroy;
    begin
      FName.Free;
      FSpeakers.Free;
    
      inherited;
    end;
    
    { TPeople }
    
    constructor TPeople.Create(const aPopulation: Int32);
    begin
      inherited Create;
      FPopulation := aPopulation;
      FLanguage := TObjectList<TLanguage>.Create;
    
    end;
    
    destructor TPeople.Destroy;
    begin
      FLanguage.Free;
      inherited;
    end;
    
    { TCountry }
    
    constructor TCountry.Create(const aName: string; const aPeople: TPeople;
      const aGeography: TGeography);
    begin
      FName := aName;
      FPeople := aPeople;
      FGeography := aGeography;
    end;
    
    destructor TCountry.Destroy;
    begin
      FPeople.Free;
      FGeography.Free;
    
      inherited;
    end;
    
    end.
    

    UDataReader.pas

    unit UDataReader;
    
    interface
    uses FlexCel.Report, Generics.Collections, DataModel;
    
    procedure LoadTables(const Report: TFlexCelReport);
    
    implementation
    procedure LoadTables(const Report: TFlexCelReport);
    var
      Countries: TObjectList<TCountry>;
      country: TCountry;
    begin
      Countries := TObjectList<TCountry>.Create;
    
      Countries.Add(TCountry.Create('China', TPeople.Create($5288AD5A), TGeography.Create(TArea.Create($420D6, $8E4F4A))));
      country := Countries[Countries.Count - 1];
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Md', 'Mandarin'), TLanguageSpeakers.Create(0, 66.2)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Yue', 'Yue'), TLanguageSpeakers.Create(0, 4.9)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Wu', 'Wu'), TLanguageSpeakers.Create(0, 6.1)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Mb', 'Minbei'), TLanguageSpeakers.Create(0, 6.2)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Mn', 'Minnan'), TLanguageSpeakers.Create(0, 5.2)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Xi', 'Xiang'), TLanguageSpeakers.Create(0, 3)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Gan', 'Gan'), TLanguageSpeakers.Create(0, 4)));
    
      Countries.Add(TCountry.Create('India', TPeople.Create($4D4C1DFA), TGeography.Create(TArea.Create($4CAD6, $2D5E09))));
      country := Countries[Countries.Count - 1];
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Hi', 'Hindi'), TLanguageSpeakers.Create(0, 43.6)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Bg', 'Bengali'), TLanguageSpeakers.Create(0, 8)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Ma', 'Marath'), TLanguageSpeakers.Create(0, 6.9)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Te', 'Telugu'), TLanguageSpeakers.Create(0, 6.7)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Ta', 'Tamil'), TLanguageSpeakers.Create(0, 5.7)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Gu', 'Gujarati'), TLanguageSpeakers.Create(0, 4.6)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Ur', 'Urdu'), TLanguageSpeakers.Create(0, 4.2)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Ka', 'Kannada'), TLanguageSpeakers.Create(0, 3.6)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Od', 'Odia'), TLanguageSpeakers.Create(0, 3.1)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Ma', 'Malayalam'), TLanguageSpeakers.Create(0, 2.9)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Pu', 'Punjabi'), TLanguageSpeakers.Create(0, 2.7)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('As', 'Assamese'), TLanguageSpeakers.Create(0, 1.3)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Mi', 'Maithili'), TLanguageSpeakers.Create(0, 1.1)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('O', 'Other'), TLanguageSpeakers.Create(0, 5.6)));
    
      Countries.Add(TCountry.Create('United States', TPeople.Create($13A00E11), TGeography.Create(TArea.Create($A7764, $8B94C9))));
      country := Countries[Countries.Count - 1];
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('En', 'English'), TLanguageSpeakers.Create(0, 78.2)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Sp', 'Spanish'), TLanguageSpeakers.Create(0, 13.4)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('Ch', 'Chinese'), TLanguageSpeakers.Create(0, 1.1)));
      country.People.Language.Add(TLanguage.Create(TLanguageName.Create('O', 'Other'), TLanguageSpeakers.Create(0, 7.3)));
      report.AddTable<TCountry>('country', Countries, TDisposeMode.DisposeAfterRun);
    
    
    end;
    
    end.
    

    UMainForm.pas

    unit UMainForm;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics,
      FlexCel.VCLSupport, FlexCel.Core, FlexCel.XlsAdapter, FlexCel.Report, FlexCel.Render,
      {$if CompilerVersion >= 23.0} System.UITypes, {$IFEND}
      ShellApi, Generics.Collections, DataModel,
      Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
    
    type
      TMainForm = class(TForm)
        btnCancel: TButton;
        btnGo: TButton;
        SaveDialog: TSaveDialog;
        Label1: TLabel;
        procedure btnCancelClick(Sender: TObject);
        procedure btnGoClick(Sender: TObject);
      private
        procedure RunReport;
        function GetDataPath: string;
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      MainForm: TMainForm;
    
    implementation
    uses IOUtils, UDataReader;
    
    {$R *.dfm}
    
    procedure TMainForm.btnCancelClick(Sender: TObject);
    begin
      Close;
    end;
    
    procedure TMainForm.btnGoClick(Sender: TObject);
    begin
      RunReport;
    
    end;
    
    function TMainForm.GetDataPath: string;
    begin
      Result := TPath.Combine(TPath.GetDirectoryName(ParamStr(0)), '..\..');
    end;
    
    
    procedure TMainForm.RunReport;
    var
      Report: TFlexCelReport;
    begin
      if not SaveDialog.Execute then exit;
    
      Report := TFlexCelReport.Create(true);
      try
        LoadTables(Report);
    
        Report.Run(
          TPath.Combine(GetDataPath, 'Advanced Reports From Lists.template.xlsx'),
          SaveDialog.FileName);
      finally
        Report.Free;
      end;
    
      if MessageDlg('Do you want to open the generated file?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
      begin
        ShellExecute(0, 'open', PCHAR(SaveDialog.FileName), nil, nil, SW_SHOWNORMAL);
      end;
    
    
    end;
    
    
    
    end.
    
    In This Article
    Back to top FlexCel Studio for VCL and FireMonkey v7.24
    © 2002 - 2025 tmssoftware.com