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;