Perplexing issues using SubReports to generate a single PDF file.
Hi,
I'm using D6 with update 2, Report Builder v6.03 and TExtraDevices.
I added code to print multiple reports to a single PDF using subreports. I
used the example from the TExtraDevices faq. It compiles and works as normal
until I print my reports to a single PDF. Then odd things begin to happen.
After printing to PDF, viewing the reports (with a TppViewer) the reports
don't generate properly as they did before printing to PDF. Some reports are
blank and others that were two pages now generates data only on the first
page. The second page generates but the data is missing. These all worked
great before printing. That's not all when I try to quit the application it
refused to close. I have to Program Reset Ctrl-F2 to get out. This is very
unusual. Then I get an error message. I use Eurekalog with my app and it
generates detailed log info about the error. It is as follows;
Exception...
Date : 11/18/2003 21:41:09
Address: 0042025E
Module : VIPWin1.exe
Type : EAccessViolation
Message: Access violation at address 0042025E in module 'VIPWin1.exe'.
Read of address 4070C008
----------------------------------------------------------------------------
--
|Address |Module |Unit |Class
|Procedure/Method|Line|
----------------------------------------------------------------------------
--
|00544525|VIPWin1.exe|ppClass.pas |TppCustomReport |RemoveBand
|5124|
|00544514|VIPWin1.exe|ppClass.pas |TppCustomReport |RemoveBand
|5123|
|00515D6A|VIPWin1.exe|ppBands.pas |TppBasicBand |Destroy |840
|
|004B002F|VIPWin1.exe|Controls.pas|TControl |Destroy
|3158|
|00475206|VIPWin1.exe|Graphics.pas|TBrush |Destroy
|1811|
|004AFF94|VIPWin1.exe|Controls.pas|TControl |Destroy
|3143|
|004B3621|VIPWin1.exe|Controls.pas|TWinControl |Destroy
|5345|
|004B3568|VIPWin1.exe|Controls.pas|TWinControl |Destroy
|5324|
|0049A068|VIPWin1.exe|Forms.pas |TScrollingWinControl|Destroy
|2024|
|0049A040|VIPWin1.exe|Forms.pas |TScrollingWinControl|Destroy
|2021|
|0049AD43|VIPWin1.exe|Forms.pas |TCustomForm |Destroy
|2585|
|00498F6F|VIPWin1.exe|Forms.pas | |DoneApplication
|1325|
|00409ED1|VIPWin1.exe|SysUtils.pas| |DoExitProc
|3248|
----------------------------------------------------------------------------
--
This doesn't seem to make sense because the master report and subreport
objects that were created were released at the end of the print process.
E.G.
//cleanup
for i := 0 to SubList.Count - 1 do
begin
TppSubReport(SubList[i]).SetReportProperty(nil);
TppSubReport(SubList[i]).Free;
end;
FreeAndNil(SubList);
FreeAndNil(MasterRpt);
If I comment out this section then the app will close correctly but the
reports still don't generate correctly as they did before master/subreports.
I'm perplexed... I have tried everything that I can think of.
Anyone have any ideas or suggestions?
Below is a snip of the code that I'm using.
Thanks in advance...
type
PRptList = ^RList;
RList = record
Rpt: TppReport;
TestId: Integer;
end;
procedure PrintBtnClick(Sender: TObject);
var
ReportNamePrefix, ReportName, DeviceType: String;
RptList: TList;
RptRecord: PRptList;
begin
try
if (PrinterNameCmb.Items[PrinterNameCmb.ItemIndex] = 'Single PDF') then
RptList := TList.Create;
DeviceType := 'Printer';
if (RptList <> nil) then
begin
ReportName := 'Multiple_Report_Single_PDF';
New(RptRecord);
RptRecord^.Rpt := R100;
RptRecord^.TestId := 0;
RptList.Add(RptRecord);
New(RptRecord);
RptRecord^.Rpt := R101;
RptRecord^.TestId := 2;
RptList.Add(RptRecord);
New(RptRecord);
RptRecord^.Rpt := R102;
RptRecord^.TestId := 4;
RptList.Add(RptRecord);
New(RptRecord);
RptRecord^.Rpt := R103;
RptRecord^.TestId := 3;
RptList.Add(RptRecord);
New(RptRecord);
RptRecord^.Rpt := R104;
RptRecord^.TestId := 1;
RptList.Add(RptRecord);
SendPrintJob(ReportName, DeviceType, RptList);
end
finally
//cleanup
if (RptList <> nil) then
begin
for i := 0 to (RptList.Count - 1) do
begin
RptRecord := RptList.Items[i];
Dispose(RptRecord);
end;
FreeAndNil(RptList);
end;
end;
end;
procedure SendPrintJob(DocName, TheDeviceType: String; RptList: TList);
var
DeviceDialog: TSaveDialog;
SubList: TList;
MasterRpt: TppReport;
SubRpt: TppSubReport;
RptName: String;
RptRecord: PRptList;
FDoPrintDevice: Boolean;
begin
//set the documentname for print manager in case user wants to cancel they
will need a recognizable name
//TheDeviceType = 'Printer' for Print to Priner or multiple report to
Single PDF file
//TheDeviceType = 'PDFFile' for printing single report to PDF file
if (TheDeviceType = 'Printer') then
begin
if (PrinterNameCmb.Items[PrinterNameCmb.ItemIndex] = 'Single PDF')
then
begin
//Show save dialog
DeviceDialog := TSaveDialog.Create(Self);
DeviceDialog.FileName := DocName + '.pdf';
DeviceDialog.DefaultExt := 'pdf';
DeviceDialog.Filter := 'PDF files (*.pdf)|*.pdf';
if (DeviceDialog.Execute) then
begin
FDoPrintDevice := True;
end;
if (FDoPrintDevice) then
begin
//create subreport list and master rpt. Add all reports in the
RPTList as sub reports to the master report
SubList := TList.Create;
MasterRpt := TppReport.Create(Self);
MasterRpt.CreateDefaultBands;
MasterRpt.RemoveBand(MasterRpt.HeaderBand);
MasterRpt.RemoveBand(MasterRpt.FooterBand);
for i := 0 to RptList.Count - 1 do
begin
SubRpt := TppSubReport.Create(Self);
SubRpt.Band := MasterRpt.DetailBand;
RptRecord := RptList[i];
SubRpt.SetReportProperty(TppReport(RptRecord.Rpt));
SubRpt.PrintBehavior := pbSection;
SubRpt.Report.PassSetting := psTwoPass;
SubRpt.ResetPageNo := False;
//use the tag to hold the studyidtestid this will be use
in each report OnBeforePrint event
SubRpt.Tag := StrToInt(IntToStr(active_study_value) +
IntToStr(RptRecord.TestId));
SubRpt.OnPrint := TppReport(RptRecord.Rpt).BeforePrint;
SubList.Add(SubRpt);
end;
MasterRpt.TextFileName := DeviceDialog.FileName;
MasterRpt.AllowPrintToFile := True;
MasterRpt.ShowPrintDialog := False;
MasterRpt.DeviceType := 'PDFFile';
//setup printer orientation
if (PortraitRB.Checked) then
MasterRpt.PrinterSetup.Orientation := poPortrait
else
MasterRpt.PrinterSetup.Orientation := poLandscape;
//setup printer paper size
case PaperSizeCmb.ItemIndex of
0: MasterRpt.PrinterSetup.PaperName := 'Letter';
1: MasterRpt.PrinterSetup.PaperName := 'Legal';
end;
//call to DoReport routine
DoReport(0,0,MasterRpt);
//cleanup
for i := 0 to SubList.Count - 1 do
begin
TppSubReport(SubList[i]).SetReportProperty(nil);
TppSubReport(SubList[i]).Free;
end;
FreeAndNil(SubList);
FreeAndNil(MasterRpt);
FDoPrintDevice := False;
end;
//cleanup
FreeAndNil(DeviceDialog);
end
else
begin
//this other stuff doesn't matter for example
end;
end;
end;
procedure DoReport(MasterRpt: TppReport);
begin
if (MasterRpt <> nil) then
begin
MasterRpt.Print;
end
else
begin
//this other stuff doesn't matter for example
end;
end;
--
John Frick
Computer & Database Programming Services
Voice: 503-251-0452 ext 9
Fax: 503-343-5154
Email: cdps@gorge.net
I'm using D6 with update 2, Report Builder v6.03 and TExtraDevices.
I added code to print multiple reports to a single PDF using subreports. I
used the example from the TExtraDevices faq. It compiles and works as normal
until I print my reports to a single PDF. Then odd things begin to happen.
After printing to PDF, viewing the reports (with a TppViewer) the reports
don't generate properly as they did before printing to PDF. Some reports are
blank and others that were two pages now generates data only on the first
page. The second page generates but the data is missing. These all worked
great before printing. That's not all when I try to quit the application it
refused to close. I have to Program Reset Ctrl-F2 to get out. This is very
unusual. Then I get an error message. I use Eurekalog with my app and it
generates detailed log info about the error. It is as follows;
Exception...
Date : 11/18/2003 21:41:09
Address: 0042025E
Module : VIPWin1.exe
Type : EAccessViolation
Message: Access violation at address 0042025E in module 'VIPWin1.exe'.
Read of address 4070C008
----------------------------------------------------------------------------
--
|Address |Module |Unit |Class
|Procedure/Method|Line|
----------------------------------------------------------------------------
--
|00544525|VIPWin1.exe|ppClass.pas |TppCustomReport |RemoveBand
|5124|
|00544514|VIPWin1.exe|ppClass.pas |TppCustomReport |RemoveBand
|5123|
|00515D6A|VIPWin1.exe|ppBands.pas |TppBasicBand |Destroy |840
|
|004B002F|VIPWin1.exe|Controls.pas|TControl |Destroy
|3158|
|00475206|VIPWin1.exe|Graphics.pas|TBrush |Destroy
|1811|
|004AFF94|VIPWin1.exe|Controls.pas|TControl |Destroy
|3143|
|004B3621|VIPWin1.exe|Controls.pas|TWinControl |Destroy
|5345|
|004B3568|VIPWin1.exe|Controls.pas|TWinControl |Destroy
|5324|
|0049A068|VIPWin1.exe|Forms.pas |TScrollingWinControl|Destroy
|2024|
|0049A040|VIPWin1.exe|Forms.pas |TScrollingWinControl|Destroy
|2021|
|0049AD43|VIPWin1.exe|Forms.pas |TCustomForm |Destroy
|2585|
|00498F6F|VIPWin1.exe|Forms.pas | |DoneApplication
|1325|
|00409ED1|VIPWin1.exe|SysUtils.pas| |DoExitProc
|3248|
----------------------------------------------------------------------------
--
This doesn't seem to make sense because the master report and subreport
objects that were created were released at the end of the print process.
E.G.
//cleanup
for i := 0 to SubList.Count - 1 do
begin
TppSubReport(SubList[i]).SetReportProperty(nil);
TppSubReport(SubList[i]).Free;
end;
FreeAndNil(SubList);
FreeAndNil(MasterRpt);
If I comment out this section then the app will close correctly but the
reports still don't generate correctly as they did before master/subreports.
I'm perplexed... I have tried everything that I can think of.
Anyone have any ideas or suggestions?
Below is a snip of the code that I'm using.
Thanks in advance...
type
PRptList = ^RList;
RList = record
Rpt: TppReport;
TestId: Integer;
end;
procedure PrintBtnClick(Sender: TObject);
var
ReportNamePrefix, ReportName, DeviceType: String;
RptList: TList;
RptRecord: PRptList;
begin
try
if (PrinterNameCmb.Items[PrinterNameCmb.ItemIndex] = 'Single PDF') then
RptList := TList.Create;
DeviceType := 'Printer';
if (RptList <> nil) then
begin
ReportName := 'Multiple_Report_Single_PDF';
New(RptRecord);
RptRecord^.Rpt := R100;
RptRecord^.TestId := 0;
RptList.Add(RptRecord);
New(RptRecord);
RptRecord^.Rpt := R101;
RptRecord^.TestId := 2;
RptList.Add(RptRecord);
New(RptRecord);
RptRecord^.Rpt := R102;
RptRecord^.TestId := 4;
RptList.Add(RptRecord);
New(RptRecord);
RptRecord^.Rpt := R103;
RptRecord^.TestId := 3;
RptList.Add(RptRecord);
New(RptRecord);
RptRecord^.Rpt := R104;
RptRecord^.TestId := 1;
RptList.Add(RptRecord);
SendPrintJob(ReportName, DeviceType, RptList);
end
finally
//cleanup
if (RptList <> nil) then
begin
for i := 0 to (RptList.Count - 1) do
begin
RptRecord := RptList.Items[i];
Dispose(RptRecord);
end;
FreeAndNil(RptList);
end;
end;
end;
procedure SendPrintJob(DocName, TheDeviceType: String; RptList: TList);
var
DeviceDialog: TSaveDialog;
SubList: TList;
MasterRpt: TppReport;
SubRpt: TppSubReport;
RptName: String;
RptRecord: PRptList;
FDoPrintDevice: Boolean;
begin
//set the documentname for print manager in case user wants to cancel they
will need a recognizable name
//TheDeviceType = 'Printer' for Print to Priner or multiple report to
Single PDF file
//TheDeviceType = 'PDFFile' for printing single report to PDF file
if (TheDeviceType = 'Printer') then
begin
if (PrinterNameCmb.Items[PrinterNameCmb.ItemIndex] = 'Single PDF')
then
begin
//Show save dialog
DeviceDialog := TSaveDialog.Create(Self);
DeviceDialog.FileName := DocName + '.pdf';
DeviceDialog.DefaultExt := 'pdf';
DeviceDialog.Filter := 'PDF files (*.pdf)|*.pdf';
if (DeviceDialog.Execute) then
begin
FDoPrintDevice := True;
end;
if (FDoPrintDevice) then
begin
//create subreport list and master rpt. Add all reports in the
RPTList as sub reports to the master report
SubList := TList.Create;
MasterRpt := TppReport.Create(Self);
MasterRpt.CreateDefaultBands;
MasterRpt.RemoveBand(MasterRpt.HeaderBand);
MasterRpt.RemoveBand(MasterRpt.FooterBand);
for i := 0 to RptList.Count - 1 do
begin
SubRpt := TppSubReport.Create(Self);
SubRpt.Band := MasterRpt.DetailBand;
RptRecord := RptList[i];
SubRpt.SetReportProperty(TppReport(RptRecord.Rpt));
SubRpt.PrintBehavior := pbSection;
SubRpt.Report.PassSetting := psTwoPass;
SubRpt.ResetPageNo := False;
//use the tag to hold the studyidtestid this will be use
in each report OnBeforePrint event
SubRpt.Tag := StrToInt(IntToStr(active_study_value) +
IntToStr(RptRecord.TestId));
SubRpt.OnPrint := TppReport(RptRecord.Rpt).BeforePrint;
SubList.Add(SubRpt);
end;
MasterRpt.TextFileName := DeviceDialog.FileName;
MasterRpt.AllowPrintToFile := True;
MasterRpt.ShowPrintDialog := False;
MasterRpt.DeviceType := 'PDFFile';
//setup printer orientation
if (PortraitRB.Checked) then
MasterRpt.PrinterSetup.Orientation := poPortrait
else
MasterRpt.PrinterSetup.Orientation := poLandscape;
//setup printer paper size
case PaperSizeCmb.ItemIndex of
0: MasterRpt.PrinterSetup.PaperName := 'Letter';
1: MasterRpt.PrinterSetup.PaperName := 'Legal';
end;
//call to DoReport routine
DoReport(0,0,MasterRpt);
//cleanup
for i := 0 to SubList.Count - 1 do
begin
TppSubReport(SubList[i]).SetReportProperty(nil);
TppSubReport(SubList[i]).Free;
end;
FreeAndNil(SubList);
FreeAndNil(MasterRpt);
FDoPrintDevice := False;
end;
//cleanup
FreeAndNil(DeviceDialog);
end
else
begin
//this other stuff doesn't matter for example
end;
end;
end;
procedure DoReport(MasterRpt: TppReport);
begin
if (MasterRpt <> nil) then
begin
MasterRpt.Print;
end
else
begin
//this other stuff doesn't matter for example
end;
end;
--
John Frick
Computer & Database Programming Services
Voice: 503-251-0452 ext 9
Fax: 503-343-5154
Email: cdps@gorge.net
This discussion has been closed.
Comments
1. Try a simple test in which you do not create the report dynamically.
2. In the code to create the report do not call Report.RemoveBand. Instead
free the band or set the Band.Report property to nil. (RemoveBand is used
internally). This code may be causing a problem.
example:
myReport.CreateDefaultBands;
myReport.HeaderBand.Free;
myReport.FooterBand.Free;
or
{alternative to the above CreateDefaultBands}
lDetailBand := TppDetailBand.Create(Self);
lDetailBand.Report := myReport;
lDetailBand.Height := 2;
3. When you free the report, the report will free the bands and objects
within the report, including the subreports.
myReport.Free;
--
Nard Moseley
Digital Metaphors
http://www.digital-metaphors.com
Best regards,
Nard Moseley
Digital Metaphors
www.digital-metaphors.com
Your solution did fix the removeband issue however it didn't resolve the
report pages issue.
Maybe we should forward this the RemoveBand solution to Jim Waler so that he
can update his TExtraDevices faq example.
Anyhow,
After printing to a single PDF using subreports, my reports still don't
generate properly. I have a report that had two pages before printing to PDF
and afterwards it only generates the first page.
The data on the first page matches but the second page doesn't generate at
all. The AbsolutePageCount= 2 before printing and afterwards (subsequent
generation) AbsolutePageCount=1.
The data pipeline is still the same and the underlying data hasn't changed.
Even more strange is if I print the report again (PDF or Paper), both pages
get generated. It's only in the viewer that the second page is missing. I
have tried Reset and ResetDevices hoping that it would fix the problem but
it still persists.
Any ideas?
Thanks...
My reports are setup PassSetting = psTwoPass and CachePages = False
If you want the reports to print with PassSetting of psTwoPass and
CachePages False, you need to configure the main report to have these
settings. The main report controls how all of the subreports are generated -
it is not possible to mix and match.
As a test try commenting out all event-handler code associated with the
report. Make sure that you do not have any code the manipulates the datasets
while the reports are generating.
--
Nard Moseley
Digital Metaphors
http://www.digital-metaphors.com
Best regards,
Nard Moseley
Digital Metaphors
www.digital-metaphors.com
I don't think that I was very clear.
Here's what I know for sure.
I have static reports. A summary report that grows depending on the amount
of data, the rest of my reports never exceed a single page.
Theses reports are viewed using TppViewer and generated with command
.PrintToDevices.
Before printing to a single PDF (master with sub-reports) everything works
just as it always has for the last 3 years.
When I want to print these reports into a single PDF file, I dynamically
create a new report and add all the reports as sub-reports.
I used the TExtraDevices faq for a code example of how to do this. My code
is almost line for line with the example. You can view the code I am using.
It is in the first post.
The command MainRpt.Print is used to generate a single PDF of all the
reports as requested.
The objects that were created during the process are then released
(object.free) as per the TExtraDevices faq.
Any subsequent requests to view the reports via the viewer I.E. calls to
.PrintToDevices causes very odd things to happen like,
The static summary report that prior to printing PDF had an
AbsolutePageCount = 2 now has an AbsolutePageCount = 1 and only one page if
viewable in the viewer.
Sometimes the page is completely blank. Sometimes it contains the correct
data that should be on the first page, but no second page is generated and
the AbsolutePageCount is still 1.
At this point if I send the reports to the printer they all print fine and
if I print the reports to a single PDF again they print fine. So subsequent
calls to the code used to generate a single PDF work just fine. These calls
all use the Print command and not PrintToDevices.
Sometimes when switching reports in the viewer (I.E. my code uses page
up/page dn keypress events to call PrintToDevice for the appropriate report)
some of the report pages will come up blank and when that occurs then I
cannot exit the application by any means except ctrl-f2.
I have tried .Reset and .ResetDevices but neither
had any effect.
The only difference is the MasterRpt and SubReport code and the odd effects
that occur on subsequent call to PrintToDevices
Now any Ideas?
Thanks...
Try downloading a trial version of RB 7.03 for D6 and performing the same
test. There was a patch to RB 7.02 that fixes a case in which stand alone
reports are used as reference style subreports.
Backup your existing installation and your existing reports prior to
installing RB 7.03.
--
Nard Moseley
Digital Metaphors
http://www.digital-metaphors.com
Best regards,
Nard Moseley
Digital Metaphors
www.digital-metaphors.com