Home General
New Blog Posts: Merging Reports - Part 1 and Part 2

Continuing Detail Band past end of dataset to end of page

edited March 2013 in General
Hi,

I have a report where the detailband has a lot of lines in it that form
various boxes / fields for the report.

This is populated with data. However, the user has requested that these
lines / boxes continue with blank / no data in them to 'fill' the rest
of the page if the data doesn't fill the page.

I was wondering - is this possible to achieve with the detail band, or
do I need to re-write the whole report using the Pagestyle for the lines
/ form?

Thanks & Regards

Adam.

Comments

  • edited March 2013
    Hi Adam,

    Take a look at the following article on adding lines to the end of the
    report. The same concept would be used in your situation.

    http://www.digital-metaphors.com/rbWiki/Delphi_Code/Formatting/How_To..._Fill_a_page_with_lines

    The PageStyle option would also work as well but as you mentioned may
    take more time to implement.

    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited March 2013
    Hi Nico,

    Thanks for your reply and example. Unfortunately that's not quite what
    I'm after - but it has given me an idea.

    What I'd like to be able to do is replicate / repeat any lines drawn in
    the detail band after the end. Using the example that was given in your
    link, I've come up with the following - but I'm not sure how to get it
    to work, and I was wondering if you could please advise?

    Thanks & Regards

    Adam.

    procedure TForm1.ppReport1EndPage(Sender: TObject);
    var
    lDrawLine: TppDrawLine;
    liTop: Integer;
    liLineTop: Integer;
    liBottom: Integer;
    i : Integer;
    begin

    if (FCurrentPosition <> -1) then
    begin
    liTop := FCurrentPosition;
    liBottom := ppReport1.Engine.PageBottom;
    liLineTop := liBottom;

    //Add a new set of lines until the page ends...
    while liTop < liLineTop do
    begin
    //First find every line that exists within
    //the detail band, and re-draw it underneath,
    //repeating until the end of the page...
    for i := 0 to self.ComponentCount - 1 do
    if self.Components[i] is TppLine then
    if TPPLine(self.Components[i]).Parent = ppDetailBand1 then
    //We've found a line that exists in the detail band...
    begin
    lDrawLine := TppDrawLine.Create(nil);

    lDrawLine.Page := ppReport1.Engine.Page;

    //Copy the line's properties to redraw.
    //Since the position are using different units of
    //measurements I have attempted to cast the lines
    //as TpPDrawLines to get the correct locations, but
    //this doesn't appear to be working correctly
    lDrawLine.Left := TppDrawLine(self.Components[i]).Left;
    lDrawLine.Top := liLineTop +
    TppDrawLine(self.Components[i]).top;
    lDrawLine.Width := TppDrawLine(self.Components[i]).Width;
    lDrawLine.Height := TppDrawLine(self.Components[i]).Height;
    end;

    {change 9075 to change the space between lines}
    //I would like to have this changed to the height of the
    //original detail band - but I'm not sure how to get the
    //height in these particular units...
    liLineTop := liLineTop - 9075;

    end;

    end;

    end;
  • edited March 2013
    Hi Adam,

    1. I recommend preforming a report object loop to find all the line
    components in the detail band. See the following article on that.

    http://www.digital-metaphors.com/rbWiki/Delphi_Code/Layouts/Report_Object_Loop

    2. The components retrieved from the loop, or the "Report.Components"
    property that you are using below returns TppComponent descendents, not
    TppDrawCommands. Typecasting them as DrawCommands will likely cause an
    error.

    Instead use "TppLine".

    lDrawLine.Left := ppToMMThousandths(TppLine(lReportComponent).Left,
    utInches, pprtHorizontal, nil);


    3. TppDrawCommand objects make measurements in microns only. The report
    components are measured with Report units (usually inches). You will
    need to convert these values so they are microns before assigning the
    DrawCommand values. Use the utilities in the ppUtils.pas file for this.

    -ppFromMMThousandths
    -ppToMMThousandths

    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited March 2013
    Hi Niko,

    Thanks very much for your reply. I've modified my code to the following
    below, but I'm still experiencing problems with it not behaving as
    expected.

    The problems I am having are as follows:


    1) The lines appear to start further to the left than expected


    2) I'm not sure what to use to change the line's orientation from
    Horizontal to Vertical for the TppLineDraw property.


    I have placed an example / demo of my current files here if this is of
    any help to see what I'm doing...

    http://www.wsdsites.net/tmp/populatetoend.zip

    Thanks & Regards

    Adam.





    if (FCurrentPosition <> -1) then
    begin
    liTop := FCurrentPosition;
    liBottom := ppReport1.Engine.PageBottom;
    liLineTop := liBottom;

    //Add a new line until space runs out on the page.
    while liTop < liLineTop do
    begin
    for i := 0 to ppDetailBand1.ObjectCount - 1 do
    if ppDetailBand1.objects[i] is TppLine then
    begin
    lDrawLine := TppDrawLine.Create(nil);
    lDrawLine.Page := ppReport1.Engine.Page;

    lDrawLine.Left :=
    ppToMMThousandths(TppLine(ppDetailBand1.objects[i]).Left, utInches,
    pprtHorizontal, nil);
    lDrawLine.Top :=
    ppToMMThousandths(TppLine(ppDetailBand1.objects[i]).Top, utInches,
    pprtVertical, nil) + liLineTop;
    lDrawLine.Width :=
    ppToMMThousandths(TppLine(ppDetailBand1.objects[i]).Width, utInches,
    pprtHorizontal, nil);
    lDrawLine.height :=
    ppToMMThousandths(TppLine(ppDetailBand1.objects[i]).height, utInches,
    pprtVertical, nil);
    lDrawLine.Weight :=
    TppLine(ppDetailBand1.objects[i]).Weight;
    lDrawLine.Pen := TppLine(ppDetailBand1.objects[i]).pen;
    // lDrawLine.Position :=
    TppLine(ppDetailBand1.objects[i]).position;

    end;

    liLineTop := liLineTop -
    (ppToMMThousandths(pPDetailBand1.Height, utInches, pprtVertical, nil));

    // liLineTop := liLineTop - 9075;


    end;

    end;

    end;
  • edited March 2013
    Hi Niko,

    I've managed to solve part of my problem. I figured I needed to take
    into account the report's margins, and have also found the
    tPPDrawLine.Position property.

    The problem I currently face though is that the additional drawing
    doesn't start directly underneath the last detail band printout. There
    is a gap - and I'm not sure what I need to take into account to reduce
    this gap.

    The updated changes I've made are still available with the previous link
    given

    http://www.wsdsites.net/tmp/populatetoend.zip

    I've changed the events to a separate procedure too - so I can use this
    on numerous reports just by making a call to the procedure.

    The updated script is also below if you don't wish to download the demo
    I've provided.

    Best Regards

    Adam.

    procedure FillPageWithBlankDetailBand(DetailBand : TppDetailBand;
    FCurrentPosition : Integer);
    var
    lDrawLine: TppDrawLine;
    liTop: Integer;
    liLineTop: Integer;
    liBottom: Integer;
    i : Integer;
    Report : TppReport;
    UnitType: TppUnitType;
    begin
    Report := TppReport(DetailBand.Report);
    UnitType := Report.Units;


    if (FCurrentPosition <> -1) then
    begin
    liTop := FCurrentPosition;
    liBottom := Report.Engine.PageBottom;
    liLineTop := liBottom;

    //Add a new line until space runs out on the page.
    while liTop < liLineTop do
    begin
    for i := 0 to DetailBand.ObjectCount - 1 do
    if DetailBand.objects[i] is TppLine then
    begin
    lDrawLine := TppDrawLine.Create(nil);
    lDrawLine.Page := Report.Engine.Page;

    lDrawLine.Left :=
    ppToMMThousandths(TppLine(DetailBand.objects[i]).Left, UnitType,
    pprtHorizontal, nil) +
    ppToMMThousandths(Report.PrinterSetup.marginLeft,
    UnitType, pprtHorizontal, nil); //Need to account for Left Margin!


    ;
    lDrawLine.Top :=
    ppToMMThousandths(TppLine(DetailBand.objects[i]).Top, UnitType,
    pprtVertical, nil) + liLineTop;
    lDrawLine.LinePosition :=
    TppLine(DetailBand.objects[i]).Position;

    lDrawLine.Width :=
    ppToMMThousandths(TppLine(DetailBand.objects[i]).Width, UnitType,
    pprtHorizontal, nil);
    lDrawLine.height :=
    ppToMMThousandths(TppLine(DetailBand.objects[i]).height, UnitType,
    pprtVertical, nil);
    lDrawLine.Weight := TppLine(DetailBand.objects[i]).Weight;
    lDrawLine.Pen := TppLine(DetailBand.objects[i]).pen;
    // lDrawLine.Position :=
    TppLine(DetailBand.objects[i]).position;
    end;

    liLineTop := liLineTop -
    (ppToMMThousandths(DetailBand.Height, UnitType, pprtVertical, nil));

    // liLineTop := liLineTop - 9075;
    end;

    end;


    end;

    procedure TForm1.ppReport1EndPage(Sender: TObject);
    begin
    FillPageWithBlankDetailBand(ppDetailBand1, FCurrentPosition);
    end;
  • edited March 2013
    Hi Adam,

    The example starts drawing lines at the bottom of the page then moves
    up, leaving a small amount of space at the top of the report rather than
    the bottom. In your case, try starting at the top and moving down.

    if (FCurrentPosition <> -1) then
    begin
    liTop := FCurrentPosition;
    liBottom := Report.Engine.PageBottom;

    //Add a new line until space runs out on the page.
    while liTop < liLineTop do
    begin
    ...

    lDrawLine.Top :=
    ppToMMThousandths(TppLine(DetailBand.objects[i]).Top, UnitType,
    pprtVertical, nil) + liTop;

    ...

    liTop := liTop + (ppToMMThousandths(DetailBand.Height,
    UnitType, pprtVertical, nil));

    end;

    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited March 2013
    Sorry, in the while loop of my example code, liLineTop should be liBottom.

    while liTop < liBottom do
    ...


    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited March 2013
    Hi Niko,

    Thanks very much for your reply. I can see now that the original demo
    was going in 'reverse', and have managed to get it to work.

    I've also aded changes to also paint shapes as well as lines if they
    exist within the detail band - and have changed the code into a
    procedure of it's own, so it can be called from multiple reports.

    This is the end result I have come up with, incase it's of any help to
    anyone else reading this down the track.

    Once again, thanks very much for your help.

    Best Regards

    Adam

    procedure FillPageWithBlankDetailBand(DetailBand : TppDetailBand;
    FCurrentPosition : Integer);
    var
    lDrawLine: TppDrawLine;
    liTop: Integer;
    liLineTop: Integer;
    liBottom: Integer;
    i : Integer;
    Report : TppReport;
    UnitType: TppUnitType;
    lDrawShape : TppDrawShape;
    begin
    {
    In order to use this, you need the following on the report itself:

    private
    FCurrentPosition : integer;


    procedure TMyForm.ppDetailBand1AfterPrint(Sender: TObject);
    begin
    inherited;
    FCurrentPosition := TpPDetailBand(sender).Report.Engine.PrintPosRect.Top;
    end;

    procedure TMyForm.PackInstDetREndPage(Sender: TObject);
    begin
    inherited;
    FillPageWithBlankDetailBand(ppDetailBand1, FCurrentPosition);
    end;



    }

    Report := TppReport(DetailBand.Report);
    UnitType := Report.Units;

    if (FCurrentPosition <> -1) then
    begin
    liTop := FCurrentPosition;
    liBottom := Report.Engine.PageBottom;
    liLineTop := FCurrentPosition;

    //Add a new line until space runs out on the page.
    while liLineTop < libottom -
    (ppToMMThousandths(DetailBand.Height, UnitType, pprtVertical, nil))
    {Give it one detail band width grace so it doesnt print over} do
    begin
    for i := 0 to DetailBand.ObjectCount - 1 do
    begin
    if DetailBand.objects[i] is TppLine then
    begin
    lDrawLine := TppDrawLine.Create(nil);
    lDrawLine.Page := Report.Engine.Page;

    lDrawLine.Left :=
    ppToMMThousandths(TppLine(DetailBand.objects[i]).Left, UnitType,
    pprtHorizontal, nil) +
    ppToMMThousandths(Report.PrinterSetup.marginLeft,
    UnitType, pprtHorizontal, nil); //Need to account for Left Margin!


    ;
    lDrawLine.Top :=
    ppToMMThousandths(TppLine(DetailBand.objects[i]).Top, UnitType,
    pprtVertical, nil) + liLineTop ;
    lDrawLine.LinePosition :=
    TppLine(DetailBand.objects[i]).Position;

    lDrawLine.Width :=
    ppToMMThousandths(TppLine(DetailBand.objects[i]).Width, UnitType,
    pprtHorizontal, nil);
    lDrawLine.height :=
    ppToMMThousandths(TppLine(DetailBand.objects[i]).height, UnitType,
    pprtVertical, nil);
    lDrawLine.Weight := TppLine(DetailBand.objects[i]).Weight;
    lDrawLine.Pen := TppLine(DetailBand.objects[i]).pen;
    // lDrawLine.Position :=
    TppLine(DetailBand.objects[i]).position;
    end;

    if DetailBand.objects[i] is tppShape then
    begin
    lDrawShape := TppDrawShape.Create(nil);
    lDrawShape.Page := Report.Engine.Page;
    lDrawShape.Left :=
    ppToMMThousandths(tppShape(DetailBand.objects[i]).Left, UnitType,
    pprtHorizontal, nil) +
    ppToMMThousandths(Report.PrinterSetup.marginLeft,
    UnitType, pprtHorizontal, nil); //Need to account for Left Margin!
    lDrawShape.Top :=
    ppToMMThousandths(tppShape(DetailBand.objects[i]).Top, UnitType,
    pprtVertical, nil) + liLineTop ;
    lDrawShape.Width :=
    ppToMMThousandths(tppShape(DetailBand.objects[i]).Width, UnitType,
    pprtHorizontal, nil);
    lDrawShape.height :=
    ppToMMThousandths(tppShape(DetailBand.objects[i]).height, UnitType,
    pprtVertical, nil);
    lDrawShape.ShapeType :=
    tppShape(DetailBand.objects[i]).Shape;
    lDrawShape.Pen := tppShape(DetailBand.objects[i]).pen;
    lDrawShape.Brush := tppShape(DetailBand.objects[i]).brush;
    // lDrawShape.Position :=
    TppLine(DetailBand.objects[i]).position;
    end;

    end;


    // liLineTop := liLineTop -
    (ppToMMThousandths(DetailBand.Height, UnitType, pprtVertical, nil));
    liLineTop := liLineTop +
    (ppToMMThousandths(DetailBand.Height, UnitType, pprtVertical, nil));

    end;


    end;


    end;
This discussion has been closed.