Report options and parameters can be:
- Initialised at any stage prior to executing the report, or in TReportWriter.OnSetupBefore.
- Modified by the user when the setup form is presented.
- Validated before the setup form is closed in TReportWriter.OnSetupValidate.
- Modified or processed by the system after the setup form is closed in TReportWriter.OnSetupAfter.
Continuing with the previous example, we can use a group box to present a date range and minimum value option for a report:
Initialising Report Option Components
Report option components can be directly set with default values at run-time, or values can be assigned some time prior to executing the report. Otherwise, use the event TReportWriter.OnSetupBefore to initialise the components. Here is an example to achieve the state illustrated, given TEdit component names eDateFrom, eDateTo and eMinValue:
procedure TForm1.ReportWriter1SetupBefore(ReportInterface: TReportInterface; ReportWriter: TReportWriter);
begin
eDateFrom.Text := FormatDateTime('dd/mm/yyyy', EncodeDate(2014, 4, 1));
eDateTo.Text := FormatDateTime('dd/mm/yyyy', EncodeDate(2015, 3, 31));
eMinValue.Text := FormatFloat('#,0', 5000);
end;
Modifying Report Options in the Setup Form
When the report executes, the report setup form can present the report option components (see previous examples) allowing the user to modify their values. Code assigned to the components might implement some relationship between different report options (eg enable one option only if a particular check box is ticked), enable the user to reference some other information in the application, or provide a shortcut to entering data etc...
Report Option Validation
The event TReportWriter.OnSetupValidate allows you to ensure that the users report option selection is valid before the setup form is closed. It is only called if the user accepts the report for output (ie not if they cancel the report). The setup form will not close unless this event handler returns "Accept = True", but it is up to you to advise the user what is wrong with their report option selection if "Accept = False".
In this case, for example, we may want to make sure that the dates entered are valid, and the "date to" does not precede the "date from". If the date range is invalid, we should tell the user and let them try again:
var
ADateFrom, ADateTo: TDateTime;
procedure TForm1.ReportWriter1SetupValidate(ReportInterface: TReportInterface;
ReportWriter: TReportWriter; SetupAction: TBatchOutputAction; var Accept: Boolean);
begin
Accept := (
TryStrToDate(eDateFrom.Text, ADateFrom) and
TryStrToDate(eDateTo.Text, ADateTo) and
(ADateFrom < ADateTo));
if not Accept then
MessageDlg('Invalid date range entered.', mtError, [mbOK], 0);
end;
Post-Setup Processing
Once report options are validated and accepted, the report options may need to be "processed" in some way for use by the report. This can be managed in the event TReportWriter.OnSetupAfter.
In this case, for example, we may wish to print the selected date range as the "PageHeaderSubTitle" to appear in the reports header details:
procedure TForm1.ReportWriter1SetupAfter(ReportInterface: TReportInterface;
ReportWriter: TReportWriter; var Accept: Boolean; var ReasonSetupRejected: string);
begin
ReportWriter.PageHeaderSubTitle := Format('%s to %s', [
FormatDateTime('d mmmm yyyy', ADateFrom),
FormatDateTime('d mmmm yyyy', ADateTo)]);
end;
Notice that OnSetupAfter also allows you to reject setup and assign details of why to the output string parameter "ReasonSetupRejected".
The difference between rejecting setup here as opposed to rejecting it in OnSetupValidate is that setting Accept = False here will not return you to the setup form to try again. This rejection is a "fatal error", causing the entire report to abort.
For example, this might be useful in a report where, given the options specified by the user, there is no matching data for the report... so it is aborted instead (without actually starting to generate the report).
procedure TForm1.ReportWriter1SetupAfter(ReportInterface: TReportInterface;
ReportWriter: TReportWriter; var Accept: Boolean; var ReasonSetupRejected: string);
begin
//check if there is any data based on the users selected report options
Accept := [retrieve dataset, check RecordCount > 0];
if not Accept then
ReasonSetupRejected := 'There is no data matching your criteria.';
end;
IMPORTANT: Rejecting the report setup in this manner does not raise an exception or display a message, but rather simply terminates the report and sets a general error state (ReportStatus = rsSetupRejected) with the ReasonSetupRejected string accessible via the AbortReasonMessage function (see notes on report error management). For example, a simple post-report response might be:
case ReportInterface1.ReportStatus of
rsSetupRejected: ShowMessage(ReportInterface1.AbortReasonMessage);
end;
Access to Report Options
Note that access to report options and parameters is direct and unrestricted. The components used to present options can be directly referenced within the report generation code - for example, if the user sets a check box option, the report can simply refer to the Checked property of that component and act accordingly. If convenient, you can use variables declared in your form unit to store interpreted options as was done above with ADateFrom and ADateTo. You can code or present report options any way you like.
This is one of the big advantages of code-based reporting!