Difference between revisions of "FPReport Usage"

From Free Pascal wiki
(Providing data to the report: - extended info about units used, and fixed the code example)
m (Providing data to the report: - another fix to the code example)
Line 47: Line 47:
 
   lReportData: TFPReportDatasetData;
 
   lReportData: TFPReportDatasetData;
 
begin
 
begin
   lReportData := TFPReportDatasetData.Create(self);
+
   lReportData := TFPReportDatasetData.Create(nil); // Same as previous code example. Use Self
   lDataSet := TDBF.Create(Self);
+
   lDataSet := TDBF.Create(nil);                     // or Nil, depending on your Application object.
 
   lDataSet.TableName := 'test.dbf';
 
   lDataSet.TableName := 'test.dbf';
 
   lReportData.DataSet := lDataSet;
 
   lReportData.DataSet := lDataSet;

Revision as of 11:47, 30 August 2017

On this page we'll dissect how to create a simple report in code. As a starting point, we take the dataset demo report from the demo application.

Owners & Parent-Child structure

All report elements (pages, bands, printable elements) are TComponent descendents. They are organised in a parent-child relation:

  • The pages are children of the report
  • The bands are children of a page
  • The printable elements are children of a band.

The owner (as in TComponent) of the various elements is not important for the report structure, but if the owner is the natural parent of a newly created component, then the parent will be set automatically.

Creating the report

Most fpReport related classes are defined in a single unit, the fpreport unit. So make sure you add that to your uses clause.

uses
  fpreport;

Everything starts with a report component:

rpt := TFPReport.Create(nil); // if your Application object is a TComponent decendant, use Self instead of nil.
rpt.Author := 'Graeme Geldenhuys';
rpt.Title := 'FPReport Demo 8 - Datasets';

The Author and Title properties can be used in expressions in the report.

Providing data to the report

Every report needs a data loop to be able to render itself. The data loop is a descendent of TFPReportData, there exist several pre-defined data loops.

One of the possible data loops is based on a dataset, TFPReportDatasetData - defined in the fpreportdb unit, so remember to add that to your uses clause. It has a Dataset property which must be set to the dataset that provides the data to the report. The loop will run over all records in the dataset, and all fields in the dataset will be available for use in expressions used in the report.

The following code creates a data loop component, and assigns a TDBF dataset to it. Note that the TDBF class is defined in the dbf unit.

var
  lDataSet: TDBF;
  lReportData: TFPReportDatasetData;
begin
  lReportData := TFPReportDatasetData.Create(nil);  // Same as previous code example. Use Self
  lDataSet := TDBF.Create(nil);                     // or Nil, depending on your Application object.
  lDataSet.TableName := 'test.dbf';
  lReportData.DataSet := lDataSet;

The lReportData component can then be used in the report structure.

Adding a page

Every report needs at least one page.

The following page is owned by the report, so it will be added automatically to the pages of the report. Once created, a page size must be set (a set of standard sizes is available), this is done through the PageSize.PaperName property. If the name is known to the global paper manager factory, then the sizes will be set automatically from the name.

p := TFPReportPage.Create(rpt);
p.Orientation := poPortrait;
p.PageSize.PaperName := 'A4';

After the page name was set, the margins can be set. The measurements are in millimeter:

{ page margins }
p.Margins.Left := 30;
p.Margins.Top := 20;
p.Margins.Right := 30;
p.Margins.Bottom := 20;

A page can have a font. This font is then used as the default for all the bands on the page. Likewise, all elements on a band will use the font of the band by default.

p.Font.Name := 'LiberationSans';

When the report must be rendered, the layouting engine will run the data loop of the page, and repeat the page as often as is needed to fit the data.

Therefor, a page must have a data loop associated with it.

p.Data := lReportData;

Adding bands to a page

Now, the page must be filled with some content. This means adding several bands to the report page.

A report title will be printed once, at the start of the report:

TitleBand := TFPReportTitleBand.Create(p);
TitleBand.Layout.Height := 40;

The width of the band must not be set, it is calculated automatically from the page width, the number of columns and the margins of the page.

A band by itself is not very useful, it serves only as a placeholder for some printable elements.

For the title page, we'll add a simple static text as the page title. All text (dynamic or static) must be added using a TFPReportMemo component:

  Memo := TFPReportMemo.Create(TitleBand);
  Memo.Layout.Left := 5;
  Memo.Layout.Top := 0;
  Memo.Layout.Width := 140;
  Memo.Layout.Height := 15;

The layout of the memo is relative to the band, and determines where the memo will be positioned.

The text of the memo, and the internal formatting can be specified using the Text and TextAlignment properties:

  Memo.Text := 'Dataset Demo';
  Memo.TextAlignment.Vertical := tlCenter;
  Memo.TextAlignment.Horizontal := taCentered;

Finally, the font and font size can be set:

  Memo.UseParentFont := False;
  Memo.Font.Color := TFPReportColor($000080);
  Memo.Font.Size := 24;

The color is a ARGB value (Alpha/Red/Green/Blue). Several pre-defined values are defined in the FPReport unit.

The loop data

The report title is printed only once, but normally a report will have a band that is printed for each record in the report loop. For this, a data band (TFPReportDataBand) must be added to the report:

DataBand := TFPReportDataBand.Create(p);
DataBand.Layout.Height := 30;
DataBand.Data:= lReportData;

This band will be repeated for every record in the data loop.

As noted above, any text must be printed with a memo. This is also true for data from the data loop. The following memo will print the name field from the dataset, prepended with the literal text "Name: "

  Memo := TFPReportMemo.Create(DataBand);
  Memo.Layout.Left := 30;
  Memo.Layout.Top := 0;
  Memo.Layout.Width := 50;
  Memo.Layout.Height := 5;
  Memo.Text := 'Name: [name]';

Expressions

Dynamic text is obtained by intermixing static text and expressions.

The expressions are anything that is between square brackets [].


The TFPExpressionParser expression engine is used to calculate the data.

That means that Expressions are much like Pascal expressions. An expression:

  • Is typed (string, integer, float, datetime)
  • can contain calculations on these types.
  • can contain report variables
  • can use data fields from the report data
  • Can use any of the pre-defined functions available from fpexprpars.

Image Support

If the dataset contains a blob field with an image, then this can also be printed:

  Image := TFPReportImage.Create(DataBand);
  Image.Layout.Top := 0;
  Image.Layout.Left := 10;
  Image.Layout.Height := 20;
  Image.Layout.Width := 14.8;
  Image.FieldName := 'Photo';
  Image.Stretched := True;

It is sufficient to set the FieldName property to the name of the field containing the image data.

A fixed image can also be added, if so desired:

  Image := TFPReportImage.Create(TitleBand);
  Image.Layout.Left := 0;
  Image.Layout.Top := 0;
  Image.Layout.Width := 40;
  Image.Layout.Height := 30;
  Image.LoadFromFile('company-logo.png');
  Image.Stretched := True;

Running the report

To layout the report, the RunReport method can be used:

rpt.RunReport;

This will create the report in memory.

It is not visible on screen, it is not saved to file.

Rendering (or exporting) the report

To actually view the report, it must be rendered or exported. A preview of the report is also an export.

Various exporters exist:

  • PDF exporter
  • FPImage exporter
  • AggPAs exporter
  • HTML exporter
  • LCL Canvas exporter, used as the basis for the LCL Preview exporter
  • FPGUI canvas exporter.

Thus, previewing or saving a layouted report is just a matter of creating the correct exporter, and calling the report RenderReport method:

FExporter:=TFPReportExportPDF.Create(Self);
Freport.RenderReport(FExporter);

back to main FPReport page