Search Results for

    Show / Hide Table of Contents

    Reading Excel files (Delphi)

    Note

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

    Overview

    A demo showing how to read the contents of an Excel file using FlexCel.

    Concepts

    • To read an Excel file you use the TXlsFile class, from where you can read and write to any Excel 2.0 or newer file.

    • To get the value for a single cell, use TXlsFile.GetCellValue.

    • To get the value for a cell when looping a full sheet, use TXlsFile.GetCellValueIndexed. It is faster than using GetCellValue since you will only read the used cells.

    • TXlsFile.GetCellValue and TXlsFile.GetCellValueIndexed will return a TCellValue that will be one of the objects allowed in an Excel cell

    • With GetCellValue and GetCellValueIndexed you will get the actual values. But if you want to actually display formatted data (for example if you have the number 2 with 2 decimals, and you want to display 2.00 instead of 2), you need to use other methods. There are 2 ways to do it:

      1. TXlsFile.GetStringFromCell will return a rich string with the cell formatted.

      2. FormatValue will format an object with a specified format and then return the corresponding rich string. TFlxNumberFormat.FormatValue is used internally by GetStringFromCell.

    • In Excel, Dates are doubles. The only difference between a date and a double is on the format on the cell. With FormatValue you can get the actual string that is displayed on Excel. Also, to convert this double to a DateTime, you can use TFlxDateTime.FromOADate.

    Files

    UReadingFiles.pas

    unit UReadingFiles;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics,
      Controls, Forms, Dialogs, ImgList, ActnList, StdCtrls,
      Tabs, Grids,ExtCtrls, ComCtrls, ToolWin, UPaths,
      FlexCel.VCLSupport, FlexCel.Core, FlexCel.XlsAdapter;
    
    type
      TFReadingFiles = class(TForm)
        ToolBar1: TToolBar;
        ToolButton1: TToolButton;
        ToolButton2: TToolButton;
        ToolButton3: TToolButton;
        ToolButton5: TToolButton;
        ToolButton4: TToolButton;
        ToolButton6: TToolButton;
        SheetData: TStringGrid;
        Tabs: TTabSet;
        Panel2: TPanel;
        Label1: TLabel;
        FmtBox: TEdit;
        Actions: TActionList;
        ActionOpen: TAction;
        ActionValueInCurrentCell: TAction;
        ActionInfo: TAction;
        ActionClose: TAction;
        OpenDialog: TOpenDialog;
        ToolbarImages: TImageList;
        StatusBar: TStatusBar;
        ToolButton7: TToolButton;
        ActionFormatValues: TAction;
        ToolbarImages_300Scale: TImageList;
        ToolbarImages_100Scale: TImageList;
        Panel1: TPanel;
        procedure ActionCloseExecute(Sender: TObject);
        procedure ActionInfoExecute(Sender: TObject);
        procedure ActionOpenExecute(Sender: TObject);
        procedure ActionValueInCurrentCellExecute(Sender: TObject);
        procedure SheetDataSelectCell(Sender: TObject; ACol, ARow: Integer;
          var CanSelect: Boolean);
        procedure ActionFormatValuesExecute(Sender: TObject);
        procedure TabsClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        UpdatingCount, UpdatingCellsCount: integer;
        Xls: TExcelFile;
    
        procedure ImportFile(const FileName: string);
        procedure FillTabs;
        procedure FillGrid(const Formatted: boolean);
        procedure SelectedCell(const aCol, aRow: integer);
        procedure AnalizeFile(const Row, Col: integer);
        function FormatValue(const v: TCellValue; const Row,
          Col: integer): String;
        procedure ClearGrid;
        procedure ResizeGrid;
        procedure BeginUpdatingGrid;
        procedure EndUpdatingGrid;
        procedure BeginUpdatingGridCells;
        procedure EndUpdatingGridCells;
        { Private declarations }
      public
        destructor Destroy; override;
        { Public declarations }
      end;
    
    var
      FReadingFiles: TFReadingFiles;
    
    implementation
    uses UFlexCelHDPI;
    
    {$R *.dfm}
    
    procedure TFReadingFiles.ActionCloseExecute(Sender: TObject);
    begin
      Close;
    end;
    
    procedure TFReadingFiles.ActionFormatValuesExecute(Sender: TObject);
    begin
      ActionFormatValues.Checked := not ActionFormatValues.Checked;
      FillGrid(ActionFormatValues.Checked);
    end;
    
    procedure TFReadingFiles.ActionInfoExecute(Sender: TObject);
    begin
      ShowMessage('This demo shows how to read the contents of an xls file' + #10 +
          'The ''Open File'' button will load an Excel file into a dataset.'+ #10 +
          'The ''Format Values'' button will apply the format to the cells, or show the raw data.'+ #10 +
          'The ''Value in Current Cell'' button will show more information about the cell selected in the grid. Try it with formulas.');
    
    end;
    
    procedure TFReadingFiles.ActionOpenExecute(Sender: TObject);
    begin
      if not OpenDialog.Execute then exit;
      ImportFile(OpenDialog.FileName);
    end;
    
    procedure TFReadingFiles.ActionValueInCurrentCellExecute(Sender: TObject);
    begin
      AnalizeFile(SheetData.Row, SheetData.Col);
    end;
    
    destructor TFReadingFiles.Destroy;
    begin
      FreeAndNil(Xls);
      inherited;
    end;
    
    procedure TFReadingFiles.SheetDataSelectCell(Sender: TObject; ACol,
      ARow: Integer; var CanSelect: Boolean);
    begin
      SelectedCell(aCol, aRow);
      CanSelect := true;
    end;
    
    procedure TFReadingFiles.TabsClick(Sender: TObject);
    begin
      FillGrid(ActionFormatValues.Checked);
    end;
    
    procedure TFReadingFiles.FillTabs;
    var
      s: integer;
    begin
    
      Tabs.Tabs.Clear;
      for s := 1 to Xls.SheetCount do
      begin
        Tabs.Tabs.Add(Xls.GetSheetName(s));
      end;
    end;
    
    
    procedure TFReadingFiles.ImportFile(const FileName: string);
    var
      StartOpen: TDateTime;
      EndOpen: TDateTime;
      EndFill: TDateTime;
    begin
       //Open the Excel file.
      if Xls = nil then Xls := TXlsFile.Create(false);
      StartOpen := Now;
      xls.Open(FileName);
      EndOpen := Now;
    
      FillTabs;
      Tabs.TabIndex := Xls.ActiveSheet - 1;
    
      EndFill := Now;
      StatusBar.SimpleText := 'Time to load file: '+  ElapsedTime(EndOpen, StartOpen) + '     Time to load file and fill grid: ' + ElapsedTime(EndFill, StartOpen);
      Caption := 'Reading Files: ' + ExtractFileName(FileName);
    end;
    
    procedure TFReadingFiles.ClearGrid;
    var
      r: integer;
    begin
      BeginUpdatingGrid;
      try
        for r := 1 to SheetData.RowCount do SheetData.Rows[r].Clear;
      finally
        EndUpdatingGrid;
      end;
    end;
    
    procedure TFReadingFiles.BeginUpdatingGrid;
    begin
      Inc(UpdatingCount);
      if (UpdatingCount = 1) then
      begin
        SendMessage(SheetData.Handle, WM_SETREDRAW, 0, 0);
      end;
    end;
    
    procedure TFReadingFiles.EndUpdatingGrid;
    begin
      Dec(UpdatingCount);
      if (UpdatingCount = 0) then
      begin
        SendMessage(SheetData.Handle, WM_SETREDRAW, 1, 0);
        RedrawWindow(SheetData.Handle, nil, 0, RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN);
      end;
    end;
    
    procedure TFReadingFiles.BeginUpdatingGridCells;
    var
      c: integer;
    begin
      Inc(UpdatingCellsCount);
      if (UpdatingCellsCount = 1) then
      begin
        for c := 1 to SheetData.ColCount do SheetData.Cols[c].BeginUpdate;
      end;
    end;
    
    procedure TFReadingFiles.EndUpdatingGridCells;
    var
      c: integer;
    begin
      Dec(UpdatingCellsCount);
      if (UpdatingCellsCount = 0) then
      begin
        for c := 1 to SheetData.ColCount do SheetData.Cols[c].EndUpdate;
      end;
    end;
    
    procedure TFReadingFiles.FillGrid(const Formatted: boolean);
    var
      r, c, cIndex: Integer;
      v: TCellValue;
    begin
      if Xls = nil then exit;
      BeginUpdatingGrid;
      try
        if (Tabs.TabIndex + 1 <= Xls.SheetCount) and (Tabs.TabIndex >= 0) then Xls.ActiveSheet := Tabs.TabIndex + 1 else Xls.ActiveSheet := 1;
        //Clear data in previous grid
        ClearGrid;
        SheetData.RowCount := 1;
        SheetData.ColCount := 1;
        FmtBox.Text := '';
    
        SheetData.RowCount := Xls.RowCount + 1; //Include fixed row
        SheetData.ColCount := Xls.ColCount + 1; //Include fixed col. NOTE THAT COLCOUNT IS SLOW. We use it here because we really need it. See the Performance.pdf doc.
    
        BeginUpdatingGridCells;
        try
    
          if (SheetData.ColCount > 1) then SheetData.FixedCols := 1; //it is deleted when we set the width to 1.
          if (SheetData.RowCount > 1) then SheetData.FixedRows := 1;
    
          for r := 1 to Xls.RowCount do
          begin
            //Instead of looping in all the columns, we will just loop in the ones that have data. This is much faster.
            for cIndex := 1 to Xls.ColCountInRow(r) do
            begin
              c := Xls.ColFromIndex(r, cIndex); //The real column.
              if Formatted then
              begin
                SheetData.Cells[c, r] := Xls.GetStringFromCell(r, c);
              end
              else
              begin
                v := Xls.GetCellValue(r, c);
                SheetData.Cells[c, r] := v.ToString;
              end;
            end;
          end;
    
          ResizeGrid;
          SelectedCell(1,1);
        finally
          EndUpdatingGridCells;
        end;
      finally
        EndUpdatingGrid;
      end;
    
    end;
    
    procedure TFReadingFiles.ResizeGrid;
    var
      r,c: integer;
    begin
      BeginUpdatingGrid;
      try
        BeginUpdatingGridCells;
        try
          if Xls = nil then
          begin
            SheetData.DefaultColWidth := Round(64.0 * Font.PixelsPerInch / 96.0);
            SheetData.DefaultRowHeight := Round(18.0 * Font.PixelsPerInch / 96.0);
            exit;
          end;
          if (Tabs.TabIndex + 1 <= Xls.SheetCount) and (Tabs.TabIndex >= 0) then Xls.ActiveSheet := Tabs.TabIndex + 1 else Xls.ActiveSheet := 1;
    
          SheetData.RowHeights[0] := Round(20 * Font.PixelsPerInch / 96.0);
          SheetData.ColWidths[0] := Round(50 * Font.PixelsPerInch / 96.0);
    
          //Fill the row headers
          for r := 1 to SheetData.RowCount - 1 do
          begin
            SheetData.Cells[0, r] := IntToStr(r);
            SheetData.RowHeights[r] := Round(Xls.GetRowHeight(r) / TExcelMetrics.RowMultDisplay(Xls) * Font.PixelsPerInch / 96.0);
          end;
    
          //Fill the column headers
          for c := 1 to SheetData.ColCount - 1 do
          begin
            SheetData.Cells[c, 0] := TCellAddress.EncodeColumn(c);
            SheetData.ColWidths[c] := Round(Xls.GetColWidth(c) / TExcelMetrics.ColMult(Xls) * Font.PixelsPerInch / 96.0);
          end;
        finally
          EndUpdatingGridCells;
        end;
      finally
        EndUpdatingGrid;
      end;
    end;
    
    
    procedure TFReadingFiles.SelectedCell(const aCol, aRow: integer);
    var
      Fmt: TFlxFormat;
    begin
      if  Xls = nil then exit;
      if (aRow < 1) or (aCol < 1) then exit;
    
      Fmt := Xls.GetCellVisibleFormatDef(aRow, aCol);
      FmtBox.Text := Fmt.Format;
    end;
    
    
    procedure TFReadingFiles.AnalizeFile(const Row, Col: integer);
    var
      v: TCellValue;
      Fmla: TFormula;
    begin
      if (Xls = nil) then
      begin
        ShowMessage('You need to open a file first');
        exit;
      end;
    
      if (Row < 1) or (Col < 1) or (Row > SheetData.RowCount - 1) or (Col > SheetData.ColCount - 1) then
      begin
        ShowMessage('The selected cell is not valid.');
        exit;
      end;
    
    
      ShowMessage(('Active sheet is "' + xls.SheetName) + '"');
      v := xls.GetCellValue(Row, Col);
    
      //First see if it is a formula
      if v.IsFormula then
      begin
        Fmla := v.AsFormula;
        ShowMessage('Cell ' + TCellAddress.Create(Row, Col).CellRef + ' contains the Formula: ' + Fmla.Text + #10 +
                    'The result of the formula is ' + FormatValue(Fmla.FormulaResult, Row, Col));
        exit;
      end;
    
      ShowMessage('Cell ' + TCellAddress.Create(Row, Col).CellRef + ' is ' + FormatValue(v, Row, Col));
    end;
    
    function TFReadingFiles.FormatValue(const v: TCellValue; const Row, Col: integer): String;
    var
      CellValue: String;
      Formatted: string;
      HasDate, HasTime: boolean;
      CellColor: TUIColor;
    begin
    
      case v.ValueType of
      TCellValueType.Empty: exit('empty');
      TCellValueType.Boolean: exit('a boolean: ' + BoolToStr(v.AsBoolean, true));
      TCellValueType.Error: exit('an error: ' + TFormulaMessages.ErrString(v.AsError));
    
      TCellValueType.Number:
        begin  //Remember, dates are doubles with date format. Also, all numbers are returned as doubles, even if they are integers.
          CellColor := TUIColor.Empty;
          CellValue := TFlxNumberFormat.FormatValue(v, xls.GetCellVisibleFormatDef(Row, Col).Format, CellColor, xls, HasDate, HasTime).ToString;
          if HasDate or HasTime then
          begin
            Result := 'a DateTime value: ' + DateTimeToStr(v.ToDateTime(xls.OptionsDates1904)) + #10 + 'The value is displayed as: ' + CellValue;
          end
          else
          begin
            Result := 'a double: ' + FloatToStr(v.AsNumber) + #10 + 'The value is displayed as: ' + CellValue + #10;
          end;
          exit;
        end;
    
      TCellValueType.DateTime:  //FlexCel won't currently return DateTime values, as dates are numbers.
      begin
        exit('a DateTime value: ' + DateTimeToStr(v.AsDateTime));
      end;
    
      TCellValueType.StringValue:
        begin
          if v.AsString.RTFRunCount > 0 then Formatted := ' FORMATTED ' else Formatted := ' ';
    
          Result := 'a' + Formatted +'string: ' + v.AsString.ToString
          + #10 + 'In html: ' + v.AsString.ToHtml(xls, xls.GetCellVisibleFormatDef(Row, Col), THtmlVersion.Html_32, THtmlStyle.Simple, TEncoding.UTF8);
          exit;
        end;
      end;
    
      raise Exception.Create('Unexpected value on cell');
    end;
    
    
    procedure TFReadingFiles.FormCreate(Sender: TObject);
    begin
      RegisterForHDPI(Self, ResizeGrid);
    end;
    
    end.
    
    In This Article
    Back to top FlexCel Studio for VCL and FireMonkey v7.24
    © 2002 - 2025 tmssoftware.com