Search Results for

    Show / Hide Table of Contents

    Manual formulas (Delphi)

    Note

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

    Overview

    Here we will create a small fully functional Minesweeper in Excel, and without any macros.

    Most of the time, you will just want to write the formulas directly on the report, and let FlexCel change them when inserting rows. But sometimes, you might want to create a formula using flexcel tags. You can do it by using <#formula> and <#ref> tags, but don't do it unless you really need to.

    Concepts

    • How to replace <#tags> inside a formula.

    • When you use the <#Formula> tag, formulas are just strings on the template. So we could define inside a cell: "<#formula>=b3", but then if we want to change the template, and insert a row below row 1, the string will still be "<#formula>=b3". That is why we need to use a <#Ref> tag. For example <#formula>=<#ref(0;-1)> on cell c3 will point to b3, but if you insert a row below row 1, it will point to b4 as it should be.

    • There is never a real need to use the <#formula> tag, you can always workaround it. On this particular case we used it so we could change the font, (since it is not possible to change the font on a conditional format), but we could have also used the approach we used on the Expression Parameters demo. In fact, it might have been better that way (by adding the <#format range> tag in the data). But this demo is to show how to use this feature, it is up to you to decide if it is worth or not.

    • How to use conditional formatting, locked cells and data validation to make a nice application.

    Files

    DataModel.pas

    unit DataModel;
    
    interface
    type
      //Delphi doesn't provide RTTI in record properties:
      //http://qc.embarcadero.com/wc/qcmain.aspx?d=78110
      //
      //As we want to use records instead of classes for simplicity,
      //we can't use properties. We'll use public fields instead.
    
      TMine = record
      public
        Value: integer;
      end;
    
      TColOfMines = record
      public
        datacol: TArray<TMine>;
    
        procedure CreateCol(const count: integer);
      end;
    
      TMines = TArray<TColOfMines>;
    
    
    implementation
    
    { TColOfMines }
    
    procedure TColOfMines.CreateCol(const count: integer);
    begin
      SetLength(DataCol, count);
    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,
      Controls, Forms, Dialogs, StdCtrls;
    
    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;
        procedure SetupMines(const MinesReport: TFlexCelReport);
        procedure AfterGenerateWorkbook(const sender: TObject;
          const e: TGenerateEventArgs);
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      MainForm: TMainForm;
    
    implementation
    uses IOUtils, DataModel;
    
    {$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.SetupMines(const MinesReport: TFlexCelReport);
    var
      Mines: TMines;
      i: Integer;
      k: Integer;
      M: TDictionary<integer, boolean>;
    begin
      Randomize;
      SetLength(Mines, 9);
    
      M := TDictionary<integer, boolean>.Create;
      try
        //We'll create 10 mines
        while M.Count < 10 do
        begin
          M.AddOrSetValue(Random(9 * 9 - 1), true);
        end;
    
    
        for i := 0 to High(Mines) do
        begin
          Mines[i].CreateCol(9);
          for k := 0 to High(Mines[i].datacol) do if M.ContainsKey(i * 9 + k) then Mines[i].datacol[k].Value := 1;
    
        end;
      finally
        M.Free;
      end;
    
      MinesReport.ClearTables;
      MinesReport.AddTable<TColOfMines>('datarow', Mines);
    
    end;
    
    procedure TMainForm.AfterGenerateWorkbook(const sender: TObject; const e: TGenerateEventArgs);
    var
      r, c: integer;
    begin
      //do some "pretty" up for the final user.
      //we could do this directly on the template, but doing it here allows us to keep the template unprotected and easier to modify.
    
      e.DataFile.ActiveSheet := 2;
      e.DataFile.SheetVisible := TXlsSheetVisible.Hidden;
      e.DataFile.ActiveSheet := 1;
      e.DataFile.Protection.SetSheetProtection('', TSheetProtectionOptions.Create(true));
      for r := 20 to TFlxConsts.Max_Rows97_2003 do e.DataFile.SetRowHidden(r, true);
      for c := 12 to TFlxConsts.Max_Columns97_2003 do e.DataFile.SetColHidden(c, true);
    
    end;
    
    procedure TMainForm.RunReport;
    var
      Report: TFlexCelReport;
    begin
      if not SaveDialog.Execute then exit;
    
      Report := TFlexCelReport.Create(true);
      try
        SetupMines(Report);
        Report.AfterGenerateWorkbook := AfterGenerateWorkbook;
        Report.Run(
          TPath.Combine(GetDataPath, 'Manual Formulas.template.xls'),
          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