Search Results for

    Show / Hide Table of Contents

    Custom previewing (Delphi)

    Note

    This demo is available in your FlexCel installation at <FlexCel Install Folder>\Demo\Delphi\Modules\25.Printing and Exporting\20.CustomPreview and also at https:​//​github.​com/​tmssoftware/​TMS-​FlexCel.​VCL-​demos/​tree/​master/​Delphi/​Modules/​25.​Printing and Exporting/​20.​Custom​Preview

    Overview

    FlexCel comes with a full featured viewer that you can use to display a preview of Excel files in your application, and without having any printer installed.

    Concepts

    • How to create a preview form that you can embed inside your application, including thumbnails, navigation, etc.

    • How to Export to PDF from a thread, allowing the user to cancel it.

    Files

    UCustomPreview.pas

    unit UCustomPreview;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics,
      Controls, Forms, Dialogs, ImgList, ActnList, StdCtrls,
      ComCtrls, ToolWin, ExtCtrls,
      FlexCel.VCLSupport, FlexCel.Core, FlexCel.XlsAdapter, FlexCel.Render, FlexCel.Preview,
      UPdfExporting, UPrinting, Menus;
    
    type
      TFCustomPreview = class(TForm)
        Actions: TActionList;
        ActionOpen: TAction;
        ActionAutofit: TAction;
        ActionRecalc: TAction;
        ActionClose: TAction;
        OpenDialog: TOpenDialog;
        ToolbarImages: TImageList;
        ActionGridLines: TAction;
        ActionHeadings: TAction;
        ActionPdf: TAction;
        ActionPrint: TAction;
        Splitter1: TSplitter;
        Panel1: TPanel;
        Panel2: TPanel;
        MainPreview: TFlexCelPreviewer;
        Panel3: TPanel;
        cbAllSheets: TCheckBox;
        Panel4: TPanel;
        Panel5: TPanel;
        Panel6: TPanel;
        Thumbs: TFlexCelPreviewer;
        PanelSheets: TPanel;
        lbSheets: TListBox;
        Splitter2: TSplitter;
        ActionZoom: TAction;
        PanelPrinting: TPanel;
        lblProgressTask: TLabel;
        PrintProgressBar: TProgressBar;
        lblPrintPage: TLabel;
        btnPrintCancel: TButton;
        PanelPdf: TPanel;
        Label1: TLabel;
        lblPdfPage: TLabel;
        PdfProgressBar: TProgressBar;
        btnPdfCancel: TButton;
        ToolbarImagesDisabled: TImageList;
        PdfSaveDialog: TSaveDialog;
        PanelPdfError: TPanel;
        lblPdfError: TLabel;
        btnPdfErrorClose: TButton;
        PanelPrintingError: TPanel;
        lblPrintingError: TLabel;
        btnPrintingErrorClose: TButton;
        PanelPrintingOk: TPanel;
        Label2: TLabel;
        btnPrintOkClose: TButton;
        PanelPdfOk: TPanel;
        Label3: TLabel;
        btnPdfOkClose: TButton;
        btnOpenGeneratedFile: TButton;
        PrintDialog: TPrintDialog;
        AutofitMenu: TPopupMenu;
        NoAutofit1: TMenuItem;
        FittoWidth1: TMenuItem;
        FittoHeight1: TMenuItem;
        FittoPage1: TMenuItem;
        FlowPanel1: TPanel;
        ToolBar2: TToolBar;
        ToolButton14: TToolButton;
        ToolButton15: TToolButton;
        ToolButton16: TToolButton;
        ToolButton17: TToolButton;
        ToolButton18: TToolButton;
        ToolBar4: TToolBar;
        ToolButtonZoom: TToolButton;
        ToolButton27: TToolButton;
        ToolButton28: TToolButton;
        ToolButton29: TToolButton;
        ToolButton30: TToolButton;
        ToolButton31: TToolButton;
        ToolButton32: TToolButton;
        PanelZoom: TPanel;
        TrackBarZoom: TTrackBar;
        btn25: TButton;
        btn50: TButton;
        btn75: TButton;
        btn100: TButton;
        btn150: TButton;
        PanelSelectPage: TPanel;
        edPage: TEdit;
        Label4: TLabel;
        lblTotalPages: TLabel;
        PanelPrint: TPanel;
        btnPrint: TButton;
        ToolbarImages_100Scale: TImageList;
        ToolbarImages_300Scale: TImageList;
        ToolBarAutofit: TToolBar;
        ToolButton2: TToolButton;
        ToolButton6: TToolButton;
        procedure ActionCloseExecute(Sender: TObject);
        procedure ActionOpenExecute(Sender: TObject);
        procedure ActionPrintExecute(Sender: TObject);
        procedure ActionPdfExecute(Sender: TObject);
        procedure btnPrintCancelClick(Sender: TObject);
        procedure btnPdfCancelClick(Sender: TObject);
        procedure btnPdfErrorCloseClick(Sender: TObject);
        procedure btnPrintingErrorCloseClick(Sender: TObject);
        procedure btnPrintOkCloseClick(Sender: TObject);
        procedure btnPdfOkCloseClick(Sender: TObject);
        procedure btnOpenGeneratedFileClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure MainPreviewZoomChanged(Sender: TObject);
        procedure ActionAutofitExecute(Sender: TObject);
        procedure ActionZoomExecute(Sender: TObject);
        procedure NoAutofit1Click(Sender: TObject);
        procedure FittoWidth1Click(Sender: TObject);
        procedure FittoHeight1Click(Sender: TObject);
        procedure FittoPage1Click(Sender: TObject);
        procedure TrackBarZoomChange(Sender: TObject);
        procedure btn25Click(Sender: TObject);
        procedure btn50Click(Sender: TObject);
        procedure btn75Click(Sender: TObject);
        procedure btn100Click(Sender: TObject);
        procedure btn150Click(Sender: TObject);
        procedure ActionRecalcExecute(Sender: TObject);
        procedure cbAllSheetsClick(Sender: TObject);
        procedure lbSheetsClick(Sender: TObject);
        procedure MainPreviewStartPageChanged(Sender: TObject);
        procedure edPageExit(Sender: TObject);
        procedure edPageKeyPress(Sender: TObject; var Key: Char);
        procedure ActionGridLinesExecute(Sender: TObject);
        procedure ActionHeadingsExecute(Sender: TObject);
        procedure TrackBarZoomEnter(Sender: TObject);
        procedure PanelZoomExit(Sender: TObject);
      private
        Xls: TExcelFile;
        ImgExport: TFlexCelImgExport;
        PrintingThread: TPrintingThread;
        PdfThread: TPdfThread;
        DisabledCount: integer;
        ChangingZoom: boolean;
        procedure EnableCommonActions(const Enable: boolean);
        procedure LoadFile(const FileName: string);
        procedure GetPassword(const e: TOnPasswordEventArgs);
        procedure UpdateZoom;
        procedure UpdateAutofitText;
        procedure UpdatePages;
        procedure ChangePages;
        procedure DPIChanged;
        { Private declarations }
      public
        destructor Destroy; override;
        { Public declarations }
      end;
    
    var
      FCustomPreview: TFCustomPreview;
    
    implementation
    uses ShellAPI, UPasswordDialog, Types, UFlexCelHDPI;
    
    {$R *.dfm}
    
    procedure TFCustomPreview.FormCreate(Sender: TObject);
    begin
      Xls := TXlsFile.Create(1, false);
      Xls.Protection.OnPassword := GetPassword;
      Xls.HeadingColWidth := -1;
      Xls.HeadingRowHeight := -1;
      ImgExport := TFlexCelImgExport.Create(Xls, false);
      ImgExport.AllVisibleSheets := false;
      MainPreview.Document := ImgExport;
      Thumbs.Document := ImgExport;
    
      if ParamCount > 0 then LoadFile(ParamStr(1)); //allow the app to be called by clicking a file in the explorer.
      RegisterForHDPI(Self, DPIChanged);
    end;
    
    destructor TFCustomPreview.Destroy;
    begin
      FreeAndNil(PrintingThread);
      FreeAndNil(PdfThread);
      FreeAndNil(ImgExport);
      FreeAndNil(Xls); //after freeing the threads, so we don't free the xls object while they are working.
    
      inherited;
    end;
    
    
    procedure TFCustomPreview.DPIChanged;
    begin
      MainPreview.InvalidatePreview;
    end;
    
    procedure TFCustomPreview.ActionCloseExecute(Sender: TObject);
    begin
      Close;
    end;
    
    procedure TFCustomPreview.GetPassword(const e: TOnPasswordEventArgs);
    var
      Pwd: TPasswordDialog;
    begin
      Pwd := TPasswordDialog.Create(self);
      try
        Pwd.SetFileName(OpenDialog.FileName);
        if Pwd.ShowModal <> mrOk then exit;
        e.Password := Pwd.Password;
      finally
        FreeAndNil(Pwd);
      end;
    end;
    
    procedure TFCustomPreview.ActionOpenExecute(Sender: TObject);
    begin
      if not OpenDialog.Execute then exit;
      LoadFile(OpenDialog.FileName);
    end;
    
    procedure TFCustomPreview.LoadFile(const FileName: string);
    var
      i: Integer;
    begin
      PanelPdfOk.Visible := false;
      PanelPdfError.Visible := false;
      PanelPdf.Visible := false;
      PanelPrintingOk.Visible := false;
      PanelPrintingError.Visible := false;
      PanelPrinting.Visible := false;
    
    
      OpenDialog.FileName := FileName;
      lbSheets.Items.Clear;
    
      try
        Xls.Open(FileName);
      except on ex: Exception do
      begin
        EnableCommonActions(false);
        ActionPrint.Enabled := false;
        ActionPdf.Enabled := false;
        ActionZoom.Enabled := false;
        ActionAutofit.Enabled := false;
        ActionOpen.Enabled := true;
        PanelSelectPage.Visible := false;
        Xls.NewFile(1, TExcelFileFormat.v2019);
        Caption := 'Custom Preview';
        ShowMessage('Error opening file: ' + ex.Message);
        MainPreview.InvalidatePreview;
        exit;
      end;
      end;
    
      for i := 1 to Xls.SheetCount do
      begin
        lbSheets.Items.Add(Xls.GetSheetName(i));
      end;
      lbSheets.ItemIndex := Xls.ActiveSheet - 1;
    
      EnableCommonActions(true);
      ActionPrint.Enabled := true;
      ActionPdf.Enabled := true;
      ActionZoom.Enabled := true;
      ActionAutofit.Enabled := true;
      Caption := 'Custom Preview: ' + OpenDialog.FileName;
      PanelSelectPage.Visible := true;
      ToolBarAutofit.Left := PanelSelectPage.Left + 10; //Make the panel appear to the left of the toolbar.
      MainPreview.InvalidatePreview;
    end;
    
    procedure TFCustomPreview.cbAllSheetsClick(Sender: TObject);
    begin
      PanelSheets.Visible := not cbAllSheets.Checked;
      ImgExport.AllVisibleSheets := cbAllSheets.Checked;
      MainPreview.InvalidatePreview();
    end;
    
    procedure TFCustomPreview.lbSheetsClick(Sender: TObject);
    begin
      if (lbSheets.Items.Count > Xls.SheetCount) or (lbSheets.ItemIndex < 0)  then exit;
      Xls.ActiveSheet := lbSheets.ItemIndex + 1;
      MainPreview.InvalidatePreview();
    end;
    
    
    procedure TFCustomPreview.EnableCommonActions(const Enable: boolean);
    begin
      if Enable then Dec(DisabledCount) else Inc(DisabledCount);
      if DisabledCount < 0 then DisabledCount := 0;
      if Enable and (DisabledCount > 0) then exit; //we would be both printing and exporting to pdf, if one finishes, the buttons shouldn't be enabled util the other finishes too.
    
    
      ActionOpen.Enabled := Enable;
      ActionGridLines.Enabled := Enable;
      ActionHeadings.Enabled := Enable;
      ActionRecalc.Enabled := Enable;
    end;
    
    
    procedure TFCustomPreview.ActionPdfExecute(Sender: TObject);
    begin
      if not PdfSaveDialog.Execute then exit;
    
      PdfProgressBar.Position := 0;
      lblPdfPage.Caption := 'Initializing';
      EnableCommonActions(false);
      ActionPdf.Enabled := false;
      btnPdfCancel.Enabled := true;
      btnPdfCancel.Caption := 'Cancel';
    
      PanelPdfOk.Visible := false;
      PanelPdfError.Visible := false;
      PanelPdf.Visible := true;
    
      FreeAndNil(PdfThread);
      PdfThread := TPdfThread.Create(
        Xls,
        procedure(Progress: integer; Msg: string)
        begin
          PdfProgressBar.Position := Progress;
          lblPdfPage.Caption := Msg;
        end,
    
        procedure(Ok: boolean; Msg: string)
        begin
          PanelPdf.Visible := false;
          if not Ok then
          begin
            PanelPdfError.Visible := true;
            lblPdfError.Caption := 'Error exporting to PDF: ' + Msg;
          end
          else
          begin
            PanelPdfOk.Visible := true;
          end;
          EnableCommonActions(true);
          ActionPdf.Enabled := true;
        end,
        PdfSaveDialog.FileName,
        cbAllSheets.Checked);
    
      PdfThread.Start;
    end;
    
    procedure TFCustomPreview.ActionPrintExecute(Sender: TObject);
    var
      PageCount: integer;
      FirstPage, TotalPages: integer;
    begin
      PrintDialog.MinPage := 1;
      PrintDialog.FromPage := 1;
    
      PageCount := ImgExport.TotalPages;
      PrintDialog.Options := [poPageNums];
      PrintDialog.MaxPage := PageCount;
      PrintDialog.ToPage := PageCount;
    
      if not PrintDialog.Execute then exit;
    
      if PrintDialog.PrintRange = prPageNums then
      begin
        FirstPage := PrintDialog.FromPage;
        TotalPages := PrintDialog.ToPage - PrintDialog.FromPage + 1;
      end else
      begin
        FirstPage := 1;
        TotalPages := -1;
      end;
    
      PrintProgressBar.Position := 0;
      lblPrintPage.Caption := 'Initializing';
      EnableCommonActions(false);
      ActionPrint.Enabled := false;
    
      btnPrintCancel.Enabled := true;
      btnPrintCancel.Caption := 'Cancel';
    
      PanelPrintingOk.Visible := false;
      PanelPrintingError.Visible := false;
      PanelPrinting.Visible := true;
    
      FreeAndNil(PrintingThread);
      PrintingThread := TPrintingThread.Create(
        Xls,
        procedure(Progress: integer; Msg: string)
        begin
          PrintProgressBar.Position := Progress;
          lblPrintPage.Caption := Msg;
        end,
    
        procedure(Ok: boolean; Msg: string)
        begin
          PanelPrinting.Visible := false;
          if not Ok then
          begin
            PanelPrintingError.Visible := true;
            lblPrintingError.Caption := 'Error printing: ' + Msg;
          end
          else
          begin
            PanelPrintingOk.Visible := true;
          end;
          EnableCommonActions(true);
          ActionPrint.Enabled := true;
        end,
        '',
        cbAllSheets.Checked,
        FirstPage,
        TotalPages);
    
      PrintingThread.Start;
    
    end;
    
    procedure TFCustomPreview.btnOpenGeneratedFileClick(Sender: TObject);
    begin
      ShellExecute(0, 'open', PChar(PdfSaveDialog.FileName), '', '', SW_SHOWNORMAL);
    end;
    
    procedure TFCustomPreview.btnPdfCancelClick(Sender: TObject);
    begin
      if PdfThread = nil then //it shouldn't really happen
      begin
        PanelPdf.Visible := false;
        exit;
      end;
      btnPdfCancel.Enabled := false;
      btnPdfCancel.Caption := 'Canceling...';
    {$IF CompilerVersion <= 22} //Delphi XE doesn't support TerminatedSet, so sadly in XE we will have to call it manually.
      PdfThread.Cancel;
    {$ifend}
      PdfThread.Terminate; //FlexCel will check that we set terminated, and exit as fast as it can.
    end;
    
    procedure TFCustomPreview.btnPrintCancelClick(Sender: TObject);
    begin
      if PrintingThread = nil then //it shouldn't really happen
      begin
        PanelPrinting.Visible := false;
        exit;
      end;
      btnPrintCancel.Enabled := false;
      btnPrintCancel.Caption := 'Canceling...';
    {$IF CompilerVersion <= 22} //Delphi XE doesn't support TerminatedSet, so sadly in XE we will have to call it manually.
      PrintingThread.Cancel;
    {$ifend}
      PrintingThread.Terminate; //FlexCel will check that we set terminated, and exit as fast as it can.
    end;
    
    procedure TFCustomPreview.btnPdfErrorCloseClick(Sender: TObject);
    begin
      PanelPdfError.Visible := false;
    end;
    
    procedure TFCustomPreview.btnPrintingErrorCloseClick(Sender: TObject);
    begin
      PanelPrintingError.Visible := false;
    end;
    
    procedure TFCustomPreview.btnPdfOkCloseClick(Sender: TObject);
    begin
      PanelPdfOk.Visible := false;
    end;
    
    procedure TFCustomPreview.btnPrintOkCloseClick(Sender: TObject);
    begin
      PanelPrintingOk.Visible := false;
    end;
    
    procedure TFCustomPreview.UpdatePages;
    begin
      edPage.Text := IntToStr(MainPreview.StartPage);
      lblTotalPages.Caption := 'of ' + IntToStr(MainPreview.TotalPages);
    end;
    
    procedure TFCustomPreview.ChangePages;
    var
      pn: integer;
    begin
      if TryStrToInt(Trim(edPage.Text), pn) then MainPreview.StartPage := pn;
    end;
    
    procedure TFCustomPreview.MainPreviewStartPageChanged(Sender: TObject);
    begin
      UpdatePages;
    end;
    
    procedure TFCustomPreview.edPageExit(Sender: TObject);
    begin
      ChangePages;
    end;
    
    procedure TFCustomPreview.edPageKeyPress(Sender: TObject; var Key: Char);
    begin
      if Key = #13 then
      begin
        ChangePages;
        Key := #0;
      end
      else if Key = #27 then
      begin
        UpdatePages;
        Key := #0;
      end;
    end;
    
    procedure TFCustomPreview.UpdateZoom;
    begin
      ActionZoom.Caption := IntToStr(Round(MainPreview.Zoom * 100)) + '%';
      if MainPreview.AutofitPreview = TAutofitPreview.None then UpdateAutofitText;
      ChangingZoom := true;
      try
        TrackBarZoom.Position := Round(MainPreview.Zoom * 100);
      finally
        ChangingZoom := false;
      end;
    end;
    
    procedure TFCustomPreview.MainPreviewZoomChanged(Sender: TObject);
    begin
      UpdateZoom;
    end;
    
    procedure TFCustomPreview.ActionZoomExecute(Sender: TObject);
    var
      p: TPoint;
    begin
      p.X := ToolButtonZoom.Left;
      p.Y := ToolButtonZoom.Top + ToolButtonZoom.Height;
      p := ToolButtonZoom.ClientToParent(p, FCustomPreview);
    
      PanelZoom.Left := p.X;
      PanelZoom.Top := p.Y;
      PanelZoom.Visible := true;
      ActiveControl := TrackBarZoom;
    end;
    
    
    procedure TFCustomPreview.btn25Click(Sender: TObject);
    begin
      MainPreview.Zoom := 0.25;
      PanelZoom.Visible := false;
    end;
    
    procedure TFCustomPreview.btn50Click(Sender: TObject);
    begin
      MainPreview.Zoom := 0.5;
      PanelZoom.Visible := false;
    end;
    
    procedure TFCustomPreview.btn75Click(Sender: TObject);
    begin
      MainPreview.Zoom := 0.75;
      PanelZoom.Visible := false;
    end;
    
    procedure TFCustomPreview.btn100Click(Sender: TObject);
    begin
      MainPreview.Zoom := 1;
      PanelZoom.Visible := false;
    end;
    
    procedure TFCustomPreview.btn150Click(Sender: TObject);
    begin
      MainPreview.Zoom := 1.5;
      PanelZoom.Visible := false;
    end;
    
    procedure TFCustomPreview.TrackBarZoomChange(Sender: TObject);
    begin
      if (ChangingZoom) then exit; //avoid recursive calls.
      MainPreview.Zoom := TrackBarZoom.Position / 100.0;
    end;
    
    procedure TFCustomPreview.TrackBarZoomEnter(Sender: TObject);
    begin
      PanelZoom.SetFocus;
    end;
    
    procedure TFCustomPreview.PanelZoomExit(Sender: TObject);
    begin
      PanelZoom.Visible := false;
    end;
    
    procedure TFCustomPreview.UpdateAutofitText;
    begin
      case MainPreview.AutofitPreview of
        TAutofitPreview.None: ActionAutofit.Caption := 'No Autofit';
        TAutofitPreview.Width: ActionAutofit.Caption := 'Fit to Width';
        TAutofitPreview.Height: ActionAutofit.Caption := 'Fit to Height';
        TAutofitPreview.Full: ActionAutofit.Caption := 'Fit to Page';
      end;
    end;
    
    procedure TFCustomPreview.ActionAutofitExecute(Sender: TObject);
    var
      PopPoint: TPoint;
    begin
      if not (Sender is TControl) then exit;
    
      PopPoint.X := (Sender as TControl).Left;
      PopPoint.Y := (Sender as TControl).Top + (Sender as TControl).Height;
      PopPoint := ClientToScreen(PopPoint);
      AutofitMenu.Popup(PopPoint.X, PopPoint.Y);
    end;
    
    procedure TFCustomPreview.NoAutofit1Click(Sender: TObject);
    begin
      MainPreview.AutofitPreview := TAutofitPreview.None;
      UpdateAutofitText;
    end;
    
    procedure TFCustomPreview.FittoWidth1Click(Sender: TObject);
    begin
      MainPreview.AutofitPreview := TAutofitPreview.Width;
      UpdateAutofitText;
    end;
    
    procedure TFCustomPreview.FittoHeight1Click(Sender: TObject);
    begin
      MainPreview.AutofitPreview := TAutofitPreview.Height;
      UpdateAutofitText;
    end;
    
    
    procedure TFCustomPreview.FittoPage1Click(Sender: TObject);
    begin
      MainPreview.AutofitPreview := TAutofitPreview.Full;
      UpdateAutofitText;
    end;
    
    procedure TFCustomPreview.ActionRecalcExecute(Sender: TObject);
    begin
      Xls.Recalc;
      MainPreview.InvalidatePreview;
    end;
    
    procedure TFCustomPreview.ActionGridLinesExecute(Sender: TObject);
    var
      i: Integer;
      SaveActiveSheet: integer;
    begin
      if cbAllSheets.Checked then
      begin
        SaveActiveSheet := Xls.ActiveSheet;
        for i := 1 to Xls.SheetCount do
        begin
          Xls.ActiveSheet := i;
          Xls.PrintGridLines := ActionGridLines.Checked;
        end;
        Xls.ActiveSheet := SaveActiveSheet;
    
      end
      else
      begin
        Xls.PrintGridLines := ActionGridLines.Checked;
      end;
      MainPreview.InvalidatePreview;
    end;
    
    procedure TFCustomPreview.ActionHeadingsExecute(Sender: TObject);
    var
      i: Integer;
      SaveActiveSheet: integer;
    begin
      if cbAllSheets.Checked then
      begin
        SaveActiveSheet := Xls.ActiveSheet;
        for i := 1 to Xls.SheetCount do
        begin
          Xls.ActiveSheet := i;
          Xls.PrintHeadings := ActionHeadings.Checked;
        end;
        Xls.ActiveSheet := SaveActiveSheet;
    
      end
      else
      begin
        Xls.PrintHeadings := ActionHeadings.Checked;
      end;
      MainPreview.InvalidatePreview;
    end;
    
    
    end.
    

    UPasswordDialog.pas

    unit UPasswordDialog;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics,
      Controls, Forms, Dialogs, StdCtrls;
    
    type
      TPasswordDialog = class(TForm)
        Label1: TLabel;
        Button1: TButton;
        Button2: TButton;
        edPassword: TEdit;
        lblFileName: TLabel;
      public
        function Password: string;
        procedure SetFileName(const FileName: string);
      end;
    
    implementation
    
    {$R *.dfm}
    
    { TPasswordDialog }
    
    function TPasswordDialog.Password: string;
    begin
      Result := edPassword.Text;
    end;
    
    procedure TPasswordDialog.SetFileName(const FileName: string);
    const
      StartChars = 10;
      MaxChars = 60;
      Ellipsis = ' ... ';
    var
      fn: string;
    begin
      fn := FileName;
      if Length(fn) > MaxChars then fn := System.Copy(FileName, 1, StartChars) + Ellipsis
          + System.Copy(FileName, Length(FileName) - (MaxChars - StartChars - Length(Ellipsis)), Length(FileName));
      lblFileName.Caption := fn;
    end;
    
    end.
    

    UPdfExporting.pas

    unit UPdfExporting;
    
    interface
    uses UProgressThread, SysUtils, FlexCel.Core, FlexCel.Render, FlexCel.Pdf;
    
    type
      TPdfThread = class(TProgressThread)
      private
        procedure ShowProgress(const sender: TObject; const e: TPageEventArgs);
      protected
        procedure Execute; override;
      end;
    
    implementation
    uses Classes, IOUtils;
    
    { TPdfThread }
    
    procedure TPdfThread.Execute;
    var
      pdf: TFlexCelPdfExport;
      fs: TFileStream;
    begin
      pdf := TFlexCelPdfExport.Create(Xls, true);
      try
        pdf.AfterGeneratePage := ShowProgress;
    
        if AllSheets then
        begin
          fs := TFileStream.Create(FileName, fmCreate);
          try
            pdf.BeginExport(fs);
            pdf.PageLayout := TPageLayout.Outlines;
            pdf.ExportAllVisibleSheets(false, TPath.GetFileNameWithoutExtension(FileName));
            pdf.EndExport;
          finally
            FreeAndNil(fs);
          end;
        end else
        begin
          pdf.Export(FileName);
        end;
      finally
        FreeAndNil(pdf);
      end;
    end;
    
    procedure TPdfThread.ShowProgress(const sender: TObject; const e: TPageEventArgs);
    var
      Prog: TFlexCelPdfExportProgress;
      Percent: Integer;
    begin
      Prog := (Sender as TFlexCelPdfExport).Progress;
      if (Prog.TotalPage = 0) then Percent := 100 else Percent := Round(Prog.Page * 100.0 / Prog.TotalPage);
    
      Synchronize(
      procedure
      begin
        ProgressFeedback(Percent, 'Page ' + IntToStr(Prog.Page) + ' of ' + IntToStr(Prog.TotalPage));
      end);
    end;
    
    end.
    

    UPrinting.pas

    unit UPrinting;
    
    interface
    uses UProgressThread, SysUtils, FlexCel.Core, FlexCel.Render, Classes;
    
    type
      TPrintingThread = class(TProgressThread)
      private
        FirstPage, TotalPages: integer;
        procedure ShowProgress(const sender: TObject; const e: TPrintPageEventArgs);
      protected
        procedure Execute; override;
      public
        constructor Create(const aXls: TExcelFile; const aProgressFeedback: TProc<integer, string>;
        const aFinalFeedback: TProc<boolean, string>; const aFileName: string;
        const aAllSheets: boolean; const aFirstPage, aTotalPages: integer);
      end;
    
    
    implementation
    
    { TPrintingThread }
    
    constructor TPrintingThread.Create(const aXls: TExcelFile;
      const aProgressFeedback: TProc<integer, string>;
      const aFinalFeedback: TProc<boolean, string>; const aFileName: string;
      const aAllSheets: boolean; const aFirstPage, aTotalPages: integer);
    begin
      inherited Create(aXls, aProgressFeedback, aFinalFeedback, aFileName, aAllSheets);
      FirstPage := aFirstPage;
      TotalPages := aTotalPages;
    end;
    
    procedure TPrintingThread.Execute;
    var
      doc: TFlexCelPrintDocument;
    begin
      inherited;
      doc := TFlexCelPrintDocument.Create(Xls);
      try
        doc.AfterGeneratePage := ShowProgress;
        if AllSheets then
        begin
          doc.BeginPrint;
          try
            doc.PrintAllVisibleSheets(false, FirstPage, TotalPages);
          finally
            doc.EndPrint;
          end;
        end else
        begin
          doc.BeginPrint;
          try
            doc.PrintSheet(1, -1, FirstPage, TotalPages);
          finally
            doc.EndPrint;
          end;
        end;
      finally
        FreeAndNil(doc);
      end;
    end;
    
    procedure TPrintingThread.ShowProgress(const sender: TObject;
      const e: TPrintPageEventArgs);
    var
      Prog: TFlexCelPrintingProgress;
      Percent: Integer;
    begin
      Prog := (Sender as TFlexCelPrintDocument).Progress;
      if (Prog.TotalPage = 0) then Percent := 100 else Percent := Round(Prog.Page * 100.0 / Prog.TotalPage);
    
      Synchronize(
      procedure
      begin
        ProgressFeedback(Percent, 'Page ' + IntToStr(Prog.Page) + ' of ' + IntToStr(Prog.TotalPage));
      end);
    end;
    
    end.
    

    UProgressThread.pas

    unit UProgressThread;
    
    interface
    uses Classes, SysUtils, FlexCel.Core;
    type
    
    TProgressThread = class(TThread)
      protected
        ProgressFeedback: TProc<integer, string>;
        FinalFeedback: TProc<boolean, string>;
        Xls: TExcelFile;
        FileName: string;
        AllSheets: boolean;
        Canceled: boolean;
    
    {$IF CompilerVersion > 22} //Delphi XE doesn't support TerminatedSet, so sadly in XE we will have to call it manually.
        procedure TerminatedSet; override;
    {$ifend}
        procedure DoTerminate; override;
      public
        constructor Create(const aXls: TExcelFile; const aProgressFeedback: TProc<integer, string>;
        const aFinalFeedback: TProc<boolean, string>; const aFileName: string; const aAllSheets: boolean);
    {$IF CompilerVersion <= 22} //Delphi XE doesn't support TerminatedSet, so sadly in XE we will have to call it manually.
         procedure Cancel;
    {$ifend}
    end;
    
    implementation
    
    { TProgressThread }
    
    constructor TProgressThread.Create(const aXls: TExcelFile;
      const aProgressFeedback: TProc<integer, string>;
      const aFinalFeedback: TProc<boolean, string>; const aFileName: string; const aAllSheets: boolean);
    
    begin
      inherited Create(True);
      FreeOnTerminate := false;
      Canceled := false;
      Xls := aXls;
      ProgressFeedback := aProgressFeedback;
      FinalFeedback := aFinalFeedback;
      FileName := aFileName;
      AllSheets := aAllSheets;
    end;
    
    procedure TProgressThread.DoTerminate;
    var
      msg: string;
      ok: boolean;
    begin
      inherited;
    
      msg := '';
      ok := not Canceled;
      if (Assigned(FatalException)) then
      begin
        ok := false;
        if FatalException is Exception then
        begin
          msg := Exception(FatalException).Message;
        end
        else msg := 'Unexpected error: ' + FatalException.ClassName;
      end;
    
      if Canceled then msg := 'Operation canceled by the user.';
    
    
      //DoTerminate runs in the thread context, not the main thread context as OnTerminate.
      Synchronize(
      procedure
      begin
        FinalFeedback(ok, msg);
      end);
    end;
    
    {$IF CompilerVersion > 22} //Delphi XE doesn't support TerminatedSet, so sadly in XE we will have to call it manually.
    procedure TProgressThread.TerminatedSet;
    begin
      inherited;
      Canceled := true;
    end;
    {$else}
    procedure TProgressThread.Cancel;  //this isn't nice, because we need to remember to call cancel instead of Terminate for our thread. But in XE there is no option.
    begin
      Canceled := true;
    end;
    {$ifend}
    end.
    
    In This Article
    Back to top FlexCel Studio for VCL and FireMonkey v7.24
    © 2002 - 2025 tmssoftware.com