Code Snippets for Images
I promised this to a few threads in this newsgroup, and also at the Oregon
DUG meeting.
This is code I use so I do not have to include TCharts in my reports--only
in my application. This way when either I make changes to the charts in my
software, or a user makes changes (eg the ability to have pie or bar series
in a given chart, or color), the reports reflect the changes made in the
application.
Some notes:
1) My application is a MDI app. All children in the app have a common
decendant, e.g.
TMyAppForm = class(TForm)
In this class I have an abstract method called GetGraphics(aChartList:
TList).
2) I save all of my reports to a Paradox table. The user can select which
report(s) the want to print. Then they are loaded into one report and
printed.
2) After loading the reports, I see what images are loaded:
function PopulateReportGraphicList (aList: TList): Boolean;
var
I: integer;
lReportGraphic: TReportGraphic;
lImg: TppImage;
begin
for I := ComponentCount-1 downto 0 do
if (Components[I] is TppImage) and
(not (TppImage(Components[I]).Band is TppPageStyle)) and
(TppImage(Components[I]).Picture.Width = 0) and
(Pos('COVER', UpperCase(TppImage(Components[I]).UserName)) = 0)
then
begin
lReportGraphic :=
TReportGraphic.Create(TppImage(Components[I]).UserName);
lImg := TppImage(Components[I]);
lReportGraphic.Rect := Rect(0, 0, Trunc(lImg.mmWidth),
Trunc(lImg.mmHeight));
aList.Add(lReportGraphic);
end;
Result := aList.Count > 0;
end;
I check to be sure it is not the cover page, as that can have images that I
do not want to overwrite. (I should probably changes this to something more
obvious, but haven't).
This creates a list of TReportGraphic objects. The implementation of
TReportGraphic object is:
TReportGraphic = class
private
FID: integer;
FMetafile: TMetafile;
FRect: TRect;
FName: string;
FScale: integer;
function GetPRect: Pointer;
public
constructor Create (aName: String);
destructor Destroy; override;
property Name: String read FName;
property ID: integer read FID write FID;
property Rect: TRect read FRect write FRect;
property PRect: Pointer read GetPRect;
property Metafile: TMetafile read FMetafile;
property Scale: integer read FScale write FScale;
end;
..
constructor TReportGraphic.Create(aName: String);
var
I: Integer;
lPos: Integer;
begin
FName := aName;
FMetafile := TMetafile.Create;
lPos := -1;
for I := 1 to Length(aName) do // Iterate
if (Copy(aName, I, 1) >= '0') and (Copy(aName, I, 1) <= '9') then
begin
lPos := I;
break;
end;
if lPos > 0 then
begin
try
FScale := StrToInt(Copy(aName, lPos, MaxInt));
if FScale < 100 then
FScale := 1000;
FName := Copy(aName, 1, lPos-1);
except
FScale := 1000;
end;
end
else
FScale := 1000;
end;
The 'scale' feature has made life a lot easier to customize the scale to the
size of chart.
I then pass the list to the active child window. That window uses the name
of the TReportGraphic to determine which chart is assigned. It calls the
method AssignChartToMetafile:
--
Ed Dressel
Some plan for retirement
Few plan for eternity.
It does little good to gain the world
Yet lose a soul.
DUG meeting.
This is code I use so I do not have to include TCharts in my reports--only
in my application. This way when either I make changes to the charts in my
software, or a user makes changes (eg the ability to have pie or bar series
in a given chart, or color), the reports reflect the changes made in the
application.
Some notes:
1) My application is a MDI app. All children in the app have a common
decendant, e.g.
TMyAppForm = class(TForm)
In this class I have an abstract method called GetGraphics(aChartList:
TList).
2) I save all of my reports to a Paradox table. The user can select which
report(s) the want to print. Then they are loaded into one report and
printed.
2) After loading the reports, I see what images are loaded:
function PopulateReportGraphicList (aList: TList): Boolean;
var
I: integer;
lReportGraphic: TReportGraphic;
lImg: TppImage;
begin
for I := ComponentCount-1 downto 0 do
if (Components[I] is TppImage) and
(not (TppImage(Components[I]).Band is TppPageStyle)) and
(TppImage(Components[I]).Picture.Width = 0) and
(Pos('COVER', UpperCase(TppImage(Components[I]).UserName)) = 0)
then
begin
lReportGraphic :=
TReportGraphic.Create(TppImage(Components[I]).UserName);
lImg := TppImage(Components[I]);
lReportGraphic.Rect := Rect(0, 0, Trunc(lImg.mmWidth),
Trunc(lImg.mmHeight));
aList.Add(lReportGraphic);
end;
Result := aList.Count > 0;
end;
I check to be sure it is not the cover page, as that can have images that I
do not want to overwrite. (I should probably changes this to something more
obvious, but haven't).
This creates a list of TReportGraphic objects. The implementation of
TReportGraphic object is:
TReportGraphic = class
private
FID: integer;
FMetafile: TMetafile;
FRect: TRect;
FName: string;
FScale: integer;
function GetPRect: Pointer;
public
constructor Create (aName: String);
destructor Destroy; override;
property Name: String read FName;
property ID: integer read FID write FID;
property Rect: TRect read FRect write FRect;
property PRect: Pointer read GetPRect;
property Metafile: TMetafile read FMetafile;
property Scale: integer read FScale write FScale;
end;
..
constructor TReportGraphic.Create(aName: String);
var
I: Integer;
lPos: Integer;
begin
FName := aName;
FMetafile := TMetafile.Create;
lPos := -1;
for I := 1 to Length(aName) do // Iterate
if (Copy(aName, I, 1) >= '0') and (Copy(aName, I, 1) <= '9') then
begin
lPos := I;
break;
end;
if lPos > 0 then
begin
try
FScale := StrToInt(Copy(aName, lPos, MaxInt));
if FScale < 100 then
FScale := 1000;
FName := Copy(aName, 1, lPos-1);
except
FScale := 1000;
end;
end
else
FScale := 1000;
end;
The 'scale' feature has made life a lot easier to customize the scale to the
size of chart.
I then pass the list to the active child window. That window uses the name
of the TReportGraphic to determine which chart is assigned. It calls the
method AssignChartToMetafile:
--
Ed Dressel
Some plan for retirement
Few plan for eternity.
It does little good to gain the world
Yet lose a soul.
This discussion has been closed.
Comments
procedure AssignChartToMetafile(aChart: TChart; aReportGraphic:
TReportGraphic);
var
I: Integer;
lMetafile: TMetafile;
lRect: TRect;
lChart : TChart;
lSeries: TChartSeries;
begin
lChart := TChart.Create(nil);
try
lChart.Assign(aChart);
for I := 0 to aChart.SeriesCount -1 do // Iterate
begin
lSeries :=
TChartSeriesClass(aChart.Series[I].ClassType).Create(lChart);
lSeries.Assign(aChart.Series[I]);
lSeries.ParentChart := lChart;
lSeries.Marks.Font.Size := 15;
lSeries.OnGetMarkText := aChart.Series[I].OnGetMarkText;
if (lSeries is TPieSeries) then
begin
// if Config.System.PieChartsIn2D then
// lChart.View3D := False;
TPieSeries(lSeries).Circled := True;
end;
end; // for
lChart.BottomAxis.LabelsFont.Size := 20;
lChart.OnGetAxisLabel := aChart.OnGetAxisLabel;
lChart.Gradient.Visible := False;
lChart.Color := clWhite;
lChart.Title.Font.Size := 25;
lChart.BottomAxis.Title.Font.Size := 25;
lChart.LeftAxis.LabelsFont.Size := 20;
lChart.LeftAxis.Title.Font.Size := 25;
lChart.Foot.Font.Size := 14;
lChart.Legend.Font.Size := 14;
lChart.BevelOuter := bvNone;
lRect := aReportGraphic.Rect;
lRect.Right := Trunc((lRect.Right * aReportGraphic.Scale) /
lRect.Bottom);
lRect.Bottom := aReportGraphic.Scale;
lMetafile := lChart.TeeCreateMetafile(False, lRect);
try
aReportGraphic.Metafile.Assign(lMetafile);
finally
lMetafile.Free;
end;
finally
lChart.Free;
// aChart.Gradient.StartColor := lColorStart;
// aChart.Gradient.EndColor := lColorEnd;
end;
end;
I then repopulate the images in the program with the TMetafiles.
HTH,
Ed Dressel
Team DM