Dynamic auto-configured subreports( looong <g> )
Hello everybody,
Scenario:
MDI App, where I need to add reports.
I created an MDI Child form which will hold a ppViewer, coupled with a
ppReport.
Now, I have several reports to be shown, and I wanted to use a report as
template,
then just load the child reports dynamically accordingly to my need.
The idea is to have a singleton list all the "child" reports will be
registered to, which
will be iterated through dinamycally at app's startup.
The main problem here is that some parts of my template can be themselves
sub-reports.
To give you an extended idea of what I'm doing, here's source code:
unit uSingleton;
interface
Type
TSingleton = class
protected
function CanCreate : Boolean;virtual;abstract;
public
constructor Create;virtual;
end;
implementation
uses SysUtils;
{ TSingleton }
constructor TSingleton.Create;
begin
inherited Create;
if Not CanCreate then
begin
raise Exception.Create( 'Singleton already exists' );
end;
end;
end.
Then I created a singleton report list:
unit uReportList;
interface
uses Contnrs, uSingleton, uReportItem;
Type
TReportList = class( TSingleton )
private
FList : TObjectList;
function GetReport(Index: Integer): TReportItem;
protected
function CanCreate : Boolean;override;
public
constructor Create;override;
destructor Destroy;override;
procedure AddReport( Rpt : TReportItem );
property Reports[ Index : Integer ] : TReportItem read GetReport;
end;
function ReportList : TReportList;
implementation
var _ReportList : TReportList;
function ReportList : TReportList;
begin
if Not Assigned( _ReportList ) then
begin
_ReportList := TReportList.Create;
end;
Result := _ReportList;
end;
{ TReportList }
procedure TReportList.AddReport(Rpt: TReportItem);
begin
FList.Add( Rpt );
end;
function TReportList.CanCreate: Boolean;
begin
Result := Not Assigned( _ReportList );
end;
constructor TReportList.Create;
begin
inherited;
FList := TObjectList.Create( True );
end;
destructor TReportList.Destroy;
begin
FList.Free;
inherited;
end;
function TReportList.GetReport(Index: Integer): TReportItem;
begin
Result := TReportItem( FList.Items[ Index ] );
end;
end.
The TReportItem class is defined here:
unit uReportItem;
interface
Type
TReportItem = class
private
FDescription: String;
procedure SetDescription(const Value: String);
public
constructor Create;virtual;
property Description : String read FDescription write SetDescription;
end;
implementation
{ TReportItem }
constructor TReportItem.Create;
begin
Inherited Create;
FDescription := '';
end;
procedure TReportItem.SetDescription(const Value: String);
begin
FDescription := Value;
end;
end.
The TReportItem class still lacks a field, which will be a class reference
for
children reports. There's in this, for me, a doubt: how should I handle it?
The problem relies in the fact that some reports can also be a part of the
report template to use AND be used as child reports.
I was thinking that the best option was to use interfaces to implement in
the
form and use a class reference to hold them, while at runtime using
different
interfaces to make them behave as I want, but I'm unsure if it wouldn't be
better to
have a base form which would "represent" the report and child forms which
would be
"seen" as actual reports... Any insight on this?
Now, I have a child form to view reports, defined as follows:
unit RepShowCode;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
BaseChildCode, Buttons, ExtCtrls, ComCtrls, ppViewr, ppDB, ppDBPipe,
ppComm, ppRelatv, ppProd, ppClass, ppReport, ppDBJIT, Db;
type
TRepShowFrm = class(TBaseChildFrm)
PnlToolBar: TPanel;
PrintBtn: TSpeedButton;
Viewer: TppViewer;
StatusBar1: TStatusBar;
InternalReport: TppReport;
InternalPipeline: TppDBPipeline;
InternalDS: TDataSource;
procedure FormShow(Sender: TObject);
private
FLogoFileName: String;
FTitle: String;
FTitleFont: TFont;
procedure SetLogoFileName(const Value: String);
procedure SetTitle(const Value: String);
procedure SetTitleFont(const Value: TFont);
{ Private declarations }
public
{ Public declarations }
property Title : String read FTitle write SetTitle;
property TitleFont : TFont read FTitleFont write SetTitleFont;
property LogoFileName : String read FLogoFileName write SetLogoFileName;
end;
var
RepShowFrm: TRepShowFrm;
implementation
{$R *.DFM}
{ TRepShowFrm }
procedure TRepShowFrm.SetLogoFileName(const Value: String);
begin
FLogoFileName := Value;
end;
procedure TRepShowFrm.SetTitle(const Value: String);
begin
FTitle := Value;
end;
procedure TRepShowFrm.SetTitleFont(const Value: TFont);
begin
FTitleFont := Value;
end;
procedure TRepShowFrm.FormShow(Sender: TObject);
begin
inherited;
Viewer.Report.PrintToDevices;
end;
end.
This one is yet to be completed, I'm unsure how I should handle the
sub-reports.
I know how to handle them technically but not conceptually. I want something
that can be easily modified and updated even if I'm not working on it( I'll
leave by
the end of the year and would like to create something easily modifiable )
Get the mess now?
Any hints on how I can make the whole thing straight-forward?
I was thinking to using interfaces, but I think it would become
quite difficult to catch conceptually and if you don't know
interfaces too good( which it may be for my colleagues ), it can
become messy.
TIA,
Andrew
Scenario:
MDI App, where I need to add reports.
I created an MDI Child form which will hold a ppViewer, coupled with a
ppReport.
Now, I have several reports to be shown, and I wanted to use a report as
template,
then just load the child reports dynamically accordingly to my need.
The idea is to have a singleton list all the "child" reports will be
registered to, which
will be iterated through dinamycally at app's startup.
The main problem here is that some parts of my template can be themselves
sub-reports.
To give you an extended idea of what I'm doing, here's source code:
unit uSingleton;
interface
Type
TSingleton = class
protected
function CanCreate : Boolean;virtual;abstract;
public
constructor Create;virtual;
end;
implementation
uses SysUtils;
{ TSingleton }
constructor TSingleton.Create;
begin
inherited Create;
if Not CanCreate then
begin
raise Exception.Create( 'Singleton already exists' );
end;
end;
end.
Then I created a singleton report list:
unit uReportList;
interface
uses Contnrs, uSingleton, uReportItem;
Type
TReportList = class( TSingleton )
private
FList : TObjectList;
function GetReport(Index: Integer): TReportItem;
protected
function CanCreate : Boolean;override;
public
constructor Create;override;
destructor Destroy;override;
procedure AddReport( Rpt : TReportItem );
property Reports[ Index : Integer ] : TReportItem read GetReport;
end;
function ReportList : TReportList;
implementation
var _ReportList : TReportList;
function ReportList : TReportList;
begin
if Not Assigned( _ReportList ) then
begin
_ReportList := TReportList.Create;
end;
Result := _ReportList;
end;
{ TReportList }
procedure TReportList.AddReport(Rpt: TReportItem);
begin
FList.Add( Rpt );
end;
function TReportList.CanCreate: Boolean;
begin
Result := Not Assigned( _ReportList );
end;
constructor TReportList.Create;
begin
inherited;
FList := TObjectList.Create( True );
end;
destructor TReportList.Destroy;
begin
FList.Free;
inherited;
end;
function TReportList.GetReport(Index: Integer): TReportItem;
begin
Result := TReportItem( FList.Items[ Index ] );
end;
end.
The TReportItem class is defined here:
unit uReportItem;
interface
Type
TReportItem = class
private
FDescription: String;
procedure SetDescription(const Value: String);
public
constructor Create;virtual;
property Description : String read FDescription write SetDescription;
end;
implementation
{ TReportItem }
constructor TReportItem.Create;
begin
Inherited Create;
FDescription := '';
end;
procedure TReportItem.SetDescription(const Value: String);
begin
FDescription := Value;
end;
end.
The TReportItem class still lacks a field, which will be a class reference
for
children reports. There's in this, for me, a doubt: how should I handle it?
The problem relies in the fact that some reports can also be a part of the
report template to use AND be used as child reports.
I was thinking that the best option was to use interfaces to implement in
the
form and use a class reference to hold them, while at runtime using
different
interfaces to make them behave as I want, but I'm unsure if it wouldn't be
better to
have a base form which would "represent" the report and child forms which
would be
"seen" as actual reports... Any insight on this?
Now, I have a child form to view reports, defined as follows:
unit RepShowCode;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
BaseChildCode, Buttons, ExtCtrls, ComCtrls, ppViewr, ppDB, ppDBPipe,
ppComm, ppRelatv, ppProd, ppClass, ppReport, ppDBJIT, Db;
type
TRepShowFrm = class(TBaseChildFrm)
PnlToolBar: TPanel;
PrintBtn: TSpeedButton;
Viewer: TppViewer;
StatusBar1: TStatusBar;
InternalReport: TppReport;
InternalPipeline: TppDBPipeline;
InternalDS: TDataSource;
procedure FormShow(Sender: TObject);
private
FLogoFileName: String;
FTitle: String;
FTitleFont: TFont;
procedure SetLogoFileName(const Value: String);
procedure SetTitle(const Value: String);
procedure SetTitleFont(const Value: TFont);
{ Private declarations }
public
{ Public declarations }
property Title : String read FTitle write SetTitle;
property TitleFont : TFont read FTitleFont write SetTitleFont;
property LogoFileName : String read FLogoFileName write SetLogoFileName;
end;
var
RepShowFrm: TRepShowFrm;
implementation
{$R *.DFM}
{ TRepShowFrm }
procedure TRepShowFrm.SetLogoFileName(const Value: String);
begin
FLogoFileName := Value;
end;
procedure TRepShowFrm.SetTitle(const Value: String);
begin
FTitle := Value;
end;
procedure TRepShowFrm.SetTitleFont(const Value: TFont);
begin
FTitleFont := Value;
end;
procedure TRepShowFrm.FormShow(Sender: TObject);
begin
inherited;
Viewer.Report.PrintToDevices;
end;
end.
This one is yet to be completed, I'm unsure how I should handle the
sub-reports.
I know how to handle them technically but not conceptually. I want something
that can be easily modified and updated even if I'm not working on it( I'll
leave by
the end of the year and would like to create something easily modifiable )
Get the mess now?
Any hints on how I can make the whole thing straight-forward?
I was thinking to using interfaces, but I think it would become
quite difficult to catch conceptually and if you don't know
interfaces too good( which it may be for my colleagues ), it can
become messy.
TIA,
Andrew
This discussion has been closed.
Comments
Not sure that I completely understand, but it sounds like it is
hierarchical:
1. List of reports that can be printed as top level reports. These are the
ReportItems.
2. Each report in number 1 above, can itself contain subreports. Therefore
the ReportItem should have a list of the childreports that it uses.
--
Nard Moseley
Digital Metaphors
http://www.digital-metaphors.com
Best regards,
Nard Moseley
Digital Metaphors
www.digital-metaphors.com
Kind of, yeah.
Not really.
There's a series of hierarchical hard-coded templates and several dynamic
"child reports". Some parts of the template can then become "child reports"
themselves, using a lower-featured template.
The point is exactly this: they cannot be determined at any time, the
templates will be invoked from a menu item( or an action ) and then
they'll be filled by the menu handler with the corresponding child report
which will be the "detail" band of the report template.
HTH understanding,
Andrew
I still do not understand. I need a more concrete example. Can you describe
a couple of the reports - how they are structured, whether they reside on a
form/datamodule or are stored as .rtm files or are stored in a database.
Somewhere there must the concept of some fundamental building blocks that
can be dyamically combined into reports.
You must know what the building blocks are, because you build a list of menu
items. Correct?
--
Nard Moseley
Digital Metaphors
http://www.digital-metaphors.com
Best regards,
Nard Moseley
Digital Metaphors
www.digital-metaphors.com
Ok.
I'm writing an E-Commerce Web application with a Delphi client, ok?
In this application I need to handle reports( orders, clients, etc ), but I
want to be able to handle company info, for example, to make small
pamphlets to distribute - for example.
Thus, I have a template like this:
------------------------------------------------------------------
| (logo) TITLE
(shop info) |
------------------------------------------------------------------
| Detail 1
|
| Detail 2
|
| etc...
|
-----------------------------------------------------------------
| Footer
|
-----------------------------------------------------------------
Now, Detail1,2, etc are "part" of the child report.
Now, say I want to make a report which looks like this:
-----------------------------------------------------------------
| SLOGAN
|
-----------------------------------------------------------------
| (logo)
|
| (shop info)
|
| Advertisment text
|
-----------------------------------------------------------------
| Footer
|
-----------------------------------------------------------------
Now you can see that the parts of the template in the first
report, now act as child reports in the detail section of the
second kind.
That's what I mean :-)
Rgds,
Andrew
Okay so now explain structurally in RB how this is currently modelled.
For example, the layout for Report1 looks like this?
main
titleband
detailband
subreport1 - pbChild
footerband
And the layout for Report2 looks like this?
main
titleband
detailband
subreport1 - pbSection - loads Report1 template?
footerband
--
Nard Moseley
Digital Metaphors
http://www.digital-metaphors.com
Best regards,
Nard Moseley
Digital Metaphors
www.digital-metaphors.com
Kinda :-)
main
( template part 1 ) title ( template part 2 )
detailband
subreport1 - pbChild
footerband
Nope, it's like this:
main
titleband
detailband
message
template part 1
footerband
template part 2
Cheers,
Andrew
I would model it as follows:
1. Template1
Create as a separate report. Then save it to an .rtm file or database table
2. Template1
Create as a separate report. Then save it to an .rtm file or database table.
3. Report1
Create layout such that Template1 and Template2 are dynamically loaded at
run-time.
4. Report2
Create layout such that Template1 and Template2 are dynamically loaded at
run-time.
--
Nard Moseley
Digital Metaphors
http://www.digital-metaphors.com
Best regards,
Nard Moseley
Digital Metaphors
www.digital-metaphors.com