Question
“My report columns will not all fit on one page. How do I extend them to the next page similar to a spread sheet?”
Solution
This can be done using multiple subreports connected to a single dataset. Each subreport will contain different columns of data, the second and so on containing the overflow columns. They can then be generated to memory and rearranged to give a spread sheet style look.
Download: SpreadSheetStyle.zip
Delphi Code Description and Examples:
The first step is to print the report to cache (memory) using a generic TppDevice object. This will allow us to access each page and rearrange them in the correct order. Below is an example of a routine that will print a report to cache.
procedure TForm1.PrintToCache;
var
lDevice: TppDevice;
begin
lDevice := TppDevice.Create(Self);
lDevice.PageSetting := psLastPage;
lDevice.Publisher := ppReport1.Publisher;
ppReport1.CachePages := True;
ppReport1.PrintToDevices;
lDevice.Free;
end;
Next we need to reorder the pages so we have a page layout similar to the following…
Subreport1: Page 1
Subreport2: Page 1
Subreport1: Page 2
Subreport2: Page 2… and so on.
To do this we first need to create a list of all the pages currently saved in memory.
lPages := TList.Create;
lPublisher := ppReport1.Publisher;
// clone all pages
for liIndex := 0 to lPublisher.PageCount-1 do
begin
lPage := lPublisher.Pages[liIndex];
lClonePage := TppPage.Create(nil);
lClonePage.Assign(lPage);
lPages.Add(lClonePage);
end;
Once we have a list of pages to work with we can begin reordering them. Each page object contains a PageNo property that needs to first be updated.
liIndex := 0;
liPageNo := 1;
while (liIndex < FFirstReportPageCount) and (FSecondReportPageCount > 0) do
begin
lFirstReportPage := lPages[liIndex];
lFirstReportPage.AbsolutePageNo := liPageNo;
lFirstReportPage.PageNo := liPageNo;
Inc(liPageNo);
lSecondReportPage := lPages[FFirstReportPageCount + liIndex];
lSecondReportPage.AbsolutePageNo := liPageNo;
lSecondReportPage.PageNo := liPageNo;
Inc(liPageNo);
Inc(liIndex);
Dec(FSecondReportPageCount);
end;
After the above has finished, we still may have extra pages left for the second subreport and we need to define the last page of the report. The following code processes any extra pages and assigns the LastPage property to the last TppPage object.
liCollatedPages := liIndex;
if (FSecondReportPageCount > 0) then
for liIndex := 0 to FSecondReportPageCount - 1 do
begin
lSecondReportPage := lPages[FFirstReportPageCount + liCollatedPages + liIndex];
lSecondReportPage.AbsolutePageNo := liPageNo;
lSecondReportPage.PageNo := liPageNo;
Inc(liPageNo);
end
else if (liCollatedPages < FFirstReportPageCount) then
begin
if (liCollatedPages > 0) then
TppPage(lPages[lPages.Count - 1]).LastPage := False;
for liIndex := liCollatedPages to FFirstReportPageCount - 1 do
begin
lFirstReportPage := lPages[liIndex];
lFirstReportPage.AbsolutePageNo := liPageNo;
lFirstReportPage.PageNo := liPageNo;
if (liPageNo = FFirstReportPageCount - 1) then
lFirstReportPage.LastPage := True;
Inc(liPageNo);
end;
end
Now we have successfully reordered the pages. The final step is to send each page back to the cache, free up any used objects to prevent memory leaks, and let the publisher know how many pages the report will be printing. Making a call to the TppReport.Print method will print the report with the newly ordered pages.
{update page cache}
for liIndex := 0 to lPages.Count - 1 do
begin
lPage := TppPage(lPages[liIndex]);
lPublisher.ReceivePage(lPage);
end;
{free old pages}
for liIndex := 0 to lPages.Count - 1 do
TppPage(lPages[liIndex]).Free;
lPages.Free;
{update page number of new pages}
for liIndex := 0 to lPublisher.PageCount - 1 do
lPublisher.Pages[liIndex].Update(nil);