Good use for subreports?
I want to have one report, but have on it, two seperate sections.
First section would be SELECT * WHERE FIELD A IS NULL.
Second section would be SELECT * WHERE FIELD B IS NULL.
I want to show first a list of a records where field A is null, then
starting on a new page a list of records where field B is null. My first
attempt was to create two subreports on the detail band. I ended up
getting only one record per page for the first section and the second
section didn't show up at all.
Is this the approach I should be working towards?
Does the detail band have to have a pipeline attached?
(new page)
Field A nulls
1 1 1
2 2 2
3 3 3
(new page)
Field B nulls
1 1 1
2 2 2
3 3 3
First section would be SELECT * WHERE FIELD A IS NULL.
Second section would be SELECT * WHERE FIELD B IS NULL.
I want to show first a list of a records where field A is null, then
starting on a new page a list of records where field B is null. My first
attempt was to create two subreports on the detail band. I ended up
getting only one record per page for the first section and the second
section didn't show up at all.
Is this the approach I should be working towards?
Does the detail band have to have a pipeline attached?
(new page)
Field A nulls
1 1 1
2 2 2
3 3 3
(new page)
Field B nulls
1 1 1
2 2 2
3 3 3
This discussion has been closed.
Comments
Be sure each subreport is connected to separate datapipelines and that the
main report is not connected to any data. Also, be sure that each dataset
is actually returning data.
If you are using Section subreports, be sure there are no bands below the
detail band or components in the detail band.
--
Regards,
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
I did have the main report hooked to a pipeline, once I removed that
things are getting a lot closer. I also had the second subreport set to
child instead of section. I also set the detail bands of the subreports
to dynamic printheight as well.
However the second section subreport prints the same record 20 times
instead of printing all 20 records in it's pipeline. And it's the first
record it keeps repeating. Any ideas?
(Delphi 6, RB 7.04)
Doh, when I copied the components from subreport1 to subreport2, it
maintained the first pipeline connection. Should have seen that sooner.
Ok, I have everything working except a a TppLabel whose OnGetText event
I assign at runtime. In the event I lookup a code and replace the a name.
if tblLookup.Locate( 'CodeField',
Pipeline.DataSource.DataSet.FieldByName( 'CodeField',
[loCaseInsensitive] ) then
Text := tblLookup.FieldByName( 'NameField' ).asString;
This works just fine in my other reports that I create at design time.
With this new report I'm loading an RTM file that I previously designed
and assigning the OnGetText event after I've loaded the file. What it
looks like is that the dataset is not moving its record pointer, it's
always showing the same record every time the OnGetText event fires.
If you are loading a template, the event handler will not be recognized
unless the event was saved with that template and it is named the same.
Otherwise you will need to assign the event in the OnLoadEnd event of the
template.
----------------------------------------------
Tech Tip: Using Template Events
----------------------------------------------
The Report.Template object has several events that can be used for
customizing what happens when a report is loaded or saved:
- OnLoadStart
- OnLoadEnd
- OnNew
- OnSaveStart
- OnSaveEnd
The OnLoadEnd and OnNew events are often used to perform actions related
to report and data initialization.
The OnSaveEnd event is often used to save additional descriptive
("meta") data to the database each time the report is saved.
Example:
The Report.Template events are public and therefore must be assigned at
run-time.
1. In the private section of your form declaration you can declare an
event-handler method:
TForm = class(TForm)
private
procedure myTemplateOnLoadEndEvent(Sender: TObject);
public
end;
2. In the Form.OnCreate event, you can assign the event-handler to the
event:
procedure TForm1.FormCreate(Sender: TObject);
begin
ppReport1.Template.OnLoadEnd := myTemplateOnLoadEndEvent;
end;
3. Implement the event-handler method:
procedure TForm1.myTemplateOnLoadEndEvent(Sender: TObject);
begin
{add code here to initial the report or data, etc. }
ppReport1.PrinterSetup.MarginTop := 0.5;
end;
--
Regards,
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Ok, after creating my TppReport I assign my OnLoadEnd event handler.
rptStatementsToProcess := TppReport.Create( nil );
rptStatementsToProcess.Template.OnLoadEnd := OnLoadEndHandler;
From within my event handler, I call a recursive method that looks for
my labels that need the OnGetText events hooked up.
procedure TPendingStatementReport.OnLoadEndHandler(Sender: TObject);
begin
AssignObjectEventHandlers( rptStatementsToProcess );
end;
However the aReport.BandCount is zero, so how would I access the two
TppLabels that I need to hookup their OnGetText events?
procedure TPendingStatementReport.AssignObjectEventHandlers( aReport:
TppCustomReport );
var
BandIdx, ObjectIdx: Integer;
begin
for BandIdx:=0 to aReport.BandCount-1 do
begin
for ObjectIdx:=0 to aReport.Bands[BandIdx].ObjectCount-1 do
if aReport.Bands[BandIdx].Objects[ObjectIdx] is TppSubReport then
AssignObjectEventHandlers(
TppCustomReport(aReport.Bands[BandIdx].Objects[ObjectIdx]) )
else if aReport.Bands[BandIdx].Objects[ObjectIdx] is TppLabel then
AssignLabelEvent(
TppLabel(aReport.Bands[BandIdx].Objects[ObjectIdx]) );
end;
end;
procedure TPendingStatementReport.AssignLabelEvent( aLabel: TppLabel );
begin
if aLabel.Name = 'pplblOPDCarrierLookup' then
aLabel.OnGetText := pplblOPDCarrierLookupGetText
else if aLabel.Name = 'pplblOPADCarrierLookup' then
aLabel.OnGetText := pplblOPADCarrierLookupGetText;
end;
The band count should never be zero if the template has already been loaded.
Below is a quick unit I created to test this and it works correctly. The
band count is always 3.
procedure TForm1.Button1Click(Sender: TObject);
begin
FReport := TppReport.Create(Self);
FReport.Template.OnLoadEnd := ReportOnLoadEndEvent;
FReport.Template.FileName := 'C:\Test.rtm';
FReport.Template.LoadFromFile;
FReport.Print;
end;
procedure TForm1.ReportOnLoadEndEvent(Sender: TObject);
var
lFont: TFont;
begin
lFont := TFont.Create;
lFont.Color := clRed;
lFont.Name := 'Arial';
lFont.Size := 12;
AssignFontToReport(lFont, FReport);
end;
procedure TForm1.AssignFontToReport(aFont: TFont; aReport: TppCustomReport);
var
liBand: Integer;
liObject: Integer;
lObject: TppComponent;
begin
for liBand := 0 to aReport.BandCount-1 do
for liObject := 0 to aReport.Bands[liBand].ObjectCount-1 do
begin
lObject := aReport.Bands[liBand].Objects[liObject];
if lObject.HasFont then
lObject.Font := aFont;
end;
end;
--
Regards,
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
to the report this afternoon and my main report had it's one detail band
which I could then traverse looking for the controls I needed to hookup
the OnGetText events for.
However when I was using a TppLabel.OnGetText to lookup a name from a
code field, my TClientDataSets didn't seem to move. The data in the
other fields was traversing just fine but in the OnGetText event, I
would try to do a locate on a lookup TTable based on a code field in the
TClientDataset which was hooked up to the TdbPipeline. The value of the
Code field in the TClientDataset however was always the same for
everyrecord.
So I changed the TppLabel to a TppDBText and hooked it up to the Code
field in the TClientDataSet and turned off my OnLoadEnd of the template
event and the Code values showed up just fine.
Then I turned on the OnLoadEnd event again to hookup the OnGetText of
the TppDBText controls and tried the same locate. Sure enough the value
of the code fields was always the same. However I thought well maybe the
Text parameter already has the correct code field and sure enough it
did. So Instead of
if LookupTable.Locate( 'Code', ClientDataSet.Field(Code),
[loCaseInsensitive] ) then
Text := LookupTable.FieldbyName( 'Name' ).asString;
I can use
if LookupTable.Locate( 'Code', Text, [loCaseInsensitive] ) then
Text := LookupTable.FieldbyName( 'Name' ).asString;
Could this be simply that I have a to old version of RB (7.04) and this
was a bug at one point? Or I'm still missing something...(more likely!).
Instead of using the locate routine, try accessing your data directly from
the pipeline. I assume your Label is located in the detail band of the
report and you are accessing the dataset that is connected to the report.
if ppReport.DataPipeline['Code'] = Text then
...
--
Regards,
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
My main report doesn't have a pipeline attached. I don't quite see what
you mean by not using the locate.
I have a TTable connected to a paradox table, which is my lookup table.
This is not in any way connected to the report.
My subreports have the following connection:
TSQLConnection->TSQLDataSet->TDataSetProvider->TClientDataSet->TDataSource->TDBPipeline->TppSubReport.
This dataset that the subreport is connected is hooked up to a Firebird
database. One of the fields in that Firebird database is a CODE field
that I need to lookup the NAME for in the paradox TTable.
The label I need to set is on the detail band of the subreport. So I
don't quite understand how your code snippet above would work.
I did try this however with the same results:
if TTable.Locate( DBPipeline.DataSource.DataSet.Field(CODE) ) then
Text := TTable.Field(NAME);
Sorry, I believe I missunderstood how your report was working. If I under
stand correctly you are taking the CODE field from the pipeline connected to
the subreport and using that value to locate another value in a different
table? If a dataset is properly connected to a report/subreport it should
traverse all the way through. If you place a DBGrid connected to the
dataset with the CODE field in it on your form and run your report, is the
cursor moving? You might try using the OnCalc event of a TppVariable and
see if that makes a difference.
--
Regards,
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com