TDBChart printed in automated background task
We have a command line program that runs via a Scheduled Task to automatically generate reports on a schedule.
These reports are made by end users in a different program. They write their own SQL and make their own RTMs (which are both then stored in our database).
When the command line program runs, it dynamically creates a TppReport, TppDBPipeline, TDataSource, and T*Qry, hooks them all up and generates the report.
This is all working fine.
Now our users have expressed a desire to put a TDBChart on their reports. At first I thought no problem, just add ppChrtDB, ppChrt, ppCTDsgn, to the uses clause. This lets it load up a report without error, but the data never gets hooked to the chart. The data can be shown via normal TppDBText and whatnot, but never to the chart.
I tried giving a username to the dynamically created TppDBPipeline that matches exactly the Username of the pipeline that was used to make the report. For example if the TDBChart looked like below, I gave the dynamically created pipeline the name "plQry":
Here's a minimal sample of the scheduled task:
These reports are made by end users in a different program. They write their own SQL and make their own RTMs (which are both then stored in our database).
When the command line program runs, it dynamically creates a TppReport, TppDBPipeline, TDataSource, and T*Qry, hooks them all up and generates the report.
This is all working fine.
Now our users have expressed a desire to put a TDBChart on their reports. At first I thought no problem, just add ppChrtDB, ppChrt, ppCTDsgn, to the uses clause. This lets it load up a report without error, but the data never gets hooked to the chart. The data can be shown via normal TppDBText and whatnot, but never to the chart.
I tried giving a username to the dynamically created TppDBPipeline that matches exactly the Username of the pipeline that was used to make the report. For example if the TDBChart looked like below, I gave the dynamically created pipeline the name "plQry":
object ppDPTeeChart1: TppDPTeeChart
DesignLayer = ppDesignLayer1
UserName = 'DPTeeChart1'
Border.mmPadding = 0
mmHeight = 52917
mmLeft = 2381
mmTop = 1588
mmWidth = 182034
BandType = 0
LayerName = Foreground
object ppDPTeeChartControl1: TppDPTeeChartControl
Left = 0
Top = 0
Width = 400
Height = 250
BackWall.Color = clWhite
Title.Text.Strings = (
'Chart')
BackColor = clWhite
MaxPointsPerPage = 0
Page = 1
ScaleLastPage = True
BevelOuter = bvNone
BorderStyle = bsNone
Color = clWhite
DefaultCanvas = 'TTeeCanvas3D'
ColorPaletteIndex = 13
object Series1: TBarSeries
DataSource = plQry
XLabelsSource = 'TYPE'
XValues.Name = 'X'
XValues.Order = loAscending
XValues.ValueSource = 'TheNumber'
YValues.Name = 'Bar'
YValues.Order = loNone
YValues.ValueSource = 'TheNumber'
end
end
end
end
Here's a minimal sample of the scheduled task:
FReportQry := TAdsQuery.Create(FConn);
FReportQry.AdsConnection := FConn;
FReportQry.SQL.Add(WorkingOnThisReport.SQL);
FReportQry.Open;
FDS := TDataSource.Create(FReportQry);
FDS.DataSet := FReportQry;
plQry := TppDBPipeline.Create(FDS);
plQry.UserName := 'plQry';
plQry.DataSource := FDS;
FReport := TppReport.Create(nil);
try
FReport.Template.SaveTo := stDatabase;
FReport.Template.DatabaseSettings.DataPipeline := PLReports;
FReport.Template.DatabaseSettings.NameField := 'ReportName';
FReport.Template.DatabaseSettings.TemplateField := 'Report';
FReport.Template.DatabaseSettings.Name := WorkingOnThisReport.ReportName;
try
FReport.Template.LoadFromDatabase;
except
on E: Exception do
begin
Logging.DoLog('Exception loading the RTM: ' + E.Message, Preferences.LoggingMechanism);
end;
end;
FReport.DataPipeline := plQry;
FReport.ShowPrintDialog := False;
FReport.ShowAutoSearchDialog := False;
FReport.ShowCancelDialog := False;
FReport.TextFileName := WorkingOnThisReport.FullReportPathAndName;
FReport.DeviceType := WorkingOnThisReport.DeviceType;
FReport.Print;
finally
FReport.Free;
end;
Comments
My guess is that the connection to the chart is being lost at some point (likely as the template is loaded but no pipeline is assigned). I suggest re-assigning the Series.Datasource property after assigning the Report.DataPipeline property and see if that resolves the problem.
You could also try tracing into the TppDPTeeChartControl.RefreshData; routine to see if the pipeline is correct. (ppChrtDP.pas)
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Is there a way I can iterate over the report components after it has been loaded from the template and detect when a chart exists?
Another thought would be to use RAP/Calc Tab to assign the Series.DataSource, but I can't find a way to access the Series in RAP.
Looking closer at your code, it appears you are assigning the owner of your dynamic objects incorrectly.
TAdsQuery.Create(FConn);
TDataSource.Create(FReportQry);
TppDBPipeline.Create(FDS);
TppReport.Create(nil);
The owner of these components would typically be the same object (a form or a data module). Start by changing this and see if it helps the issue.
If not, take a look at a report object loop to find report components.
https://rbwiki.digital-metaphors.com/delphi-code/layouts-delphi-code/report-object-loop/
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
for liBand := 0 to FReport.BandCount-1 do begin for liObject := 0 to FReport.Bands[liBand].ObjectCount-1 do begin lObject := FReport.Bands[liBand].Objects[liObject]; //would need to put this in it's own procedure and recursively call it if we used subreports if (lObject is TppDPTeeChart) then begin for liSeries := 0 to (lObject AS TppDPTeeChart).Chart.SeriesCount - 1 do begin lSeries := (lObject AS TppDPTeeChart).Chart.Series[liSeries]; if lSeries.FunctionType = nil then lSeries.DataSource := PLUserDefinedExport else lSeries.DataSource := (lObject as TppDPTeeChart).Chart.Series[0]; end; end; end; end;