How To…Prevent an Orphaned Summary Band

Question

“The summary band of my report displays alone on the last page of my report. Is there a way to move the last detail band to the next page to prevent this behavior?”

Solution

This can be done by measuring the amount of space the last detail plus the summary band take on the last page of the report. If there is not enough space to fit both bands, manually move the drawcommands from the last detail band to the next page.
See the following example for how this can be done using the DetailBand.BeforePrint, AfterPrint, and Report.EndPage events.

Download: DetailForOrphanSummary.zip

Sample Delphi code:

1. First determine if there is enough space for both the last detail band and the summary band on the last page of the report.

procedure TForm1.ppDetailBand1BeforePrint(Sender: TObject);
var
  liMarginBottom: Integer;
  liMarginTop: Integer;
  liAvailableSpace: Integer;
  ldSpaceNeededInInches: Double;
  ldAvailableSpaceInInches: Double;
begin

  liAvailableSpace := ppReport1.PrinterSetup.PageDef.mmPrintableHeight - ppReport1.Engine.PrintPosRect.Top;

  ldAvailableSpaceInInches := ppFromMMTHousandths(liAvailableSpace, utInches, pprtVertical, ppReport1.Printer);

  ldSpaceNeededInInches := ppDetailBand1.Height + ppSummaryBand1.Height;

  if (ldAvailableSpaceInInches < ldSpaceNeededInInches) then
    FDetailStartingPosition := ppReport1.Engine.PrintposRect.Top;

  FDrawCommandStartIndex := ppReport1.Engine.Page.DrawCommandCount;

end;

2. If there is not enough space, remove the last detail band’s drawcommands from the page and save them to a list for later use.

procedure TForm1.ppReport1EndPage(Sender: TObject);
var
  I: Integer;
  liIndex: Integer;
  lDrawCommand: TppDrawCommand;
begin

  if not(FLastDetailMoved) and ppReport1.DataPipeline.EOF then
    begin

      FLastDetailMoved := True;

      for liIndex := FDrawCommandStartIndex to FDrawCommandEndIndex do
        begin
          lDrawCommand := TppDrawCommand(ppReport1.Engine.Page.DrawCommands[liIndex]);
          FDrawCommands.Add(lDrawCommand);
        end;

      for liIndex := 0 to FDrawCommands.Count - 1 do
        TppDrawCommand(FDrawCommands[liIndex]).Page := nil;

    end;

end;

3. After the next page starts, add the saved drawcommands at the top and move the cursor down so the summary band will print below.

procedure TForm1.ppHeaderBand1AfterPrint(Sender: TObject);
var
  liDetailHeight: Integer;
  liHeaderHeight: Integer;
  liRight: Integer;
  liLeft: Integer;
  liBottom: Integer;
  liTop: Integer;
  liIndex: Integer;
  lDrawCommand: TppDrawCommand;
begin

  if ppReport1.DataPipeline.EOF then
    begin

      liHeaderHeight := ppToMMThousandths(ppHeaderband1.Height, utInches, pprtVertical, nil);
      liDetailHeight := ppToMMThousandths(ppDetailband1.Height, utInches, pprtVertical, nil);

      for liIndex := 0 to FDrawCommands.Count - 1 do
        begin
          lDrawCommand := TppDrawCommand(FDrawCommands[liIndex]);

          lDrawCommand.Page := ppReport1.Engine.Page;

          {also need to take into account the header height in microns too if you have a header band of group header band}
          lDrawCommand.Top := ppReport1.Engine.PrintPosRect.Top + lDrawCommand.Top - FDetailStartingPosition;
        end;

      liTop := ppReport1.Engine.PrintPosRect.Top + liDetailHeight;
      liLeft := ppReport1.Engine.PrintPosRect.Left;
      liBottom := ppReport1.Engine.PrintPosRect.Bottom;
      liRight := ppReport1.Engine.PrintPosRect.Right;

      ppReport1.Engine.SetPrintPosition(liLeft, liTop, liRight, liBottom);

    end
  else
    FDrawCommands.Clear;

end;