 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Andrea Raimondi Guest
|
Posted: Thu Nov 27, 2003 10:06 am Post subject: Designing a report template using Report Builder |
|
|
Hello Peers,
This is my plan: I want to create a series of child reports to use with
ReportBuilder and assign them to the main report to be displayed.
What I was thinking is:
I inherit a child form from my TBaseChildFrm, to hold a ppViewer.
Then, I create several datamodules which will hold the various ppReports.
Now my doubt: is this a good solution? Have you done something like
this before? What are the pitfalls of this approach?
TIA,
Andrew
|
|
| Back to top |
|
 |
Andrea Raimondi Guest
|
Posted: Mon Dec 01, 2003 10:04 am Post subject: Re: Designing a report template using Report Builder( quite |
|
|
Andrea Raimondi wrote:
<snip>
Since nobody gave an insight, I've started it in this way:
First of all, I used an abstract factory for singletons, like this:
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 )
Any hints?
TIA,
Andrew
|
|
| Back to top |
|
 |
Yoav Guest
|
Posted: Sun Dec 28, 2003 5:21 pm Post subject: Singleton - Another way. |
|
|
Hi Andrea,
I can suggest a better implementation of a Singleton class then the one
you have. Your implementation allows to create multiple copies of the
same object if sub-classes are not implemented right, and requires work
from the developer of the child class. At most, the user will get an
exception when he creates the second instance.
My implementation does not require any work from the writer of the
derived class. Instead of raising an exception when a second copy is
created, it simply returns the first object copy. The free method does
nothing, and the object is automatically distroyed when the application
ends.
My Implementation:
unit uSingleton;
interface
Uses
SysUtils;
Type
TSingleton = class(TObject)
Private
Procedure Dispose;
protected
Procedure Init; Virtual;
Procedure BeforeDestroy; Virtual;
Public
class Function NewInstance: TObject; Override;
Procedure FreeInstance; Override;
End;
implementation
Var
SingletonHash: TStringList;
// In my original code I use a true Hash Table, but as delphi does not
provide
// one built it, I replaced it here with a TStringList. It should be easy
// to replace with a true hash table if you have one.
{ General}
Procedure ClearSingletons;
Var
I: Integer;
Begin
// call BeforeDestroy for all singleton objects.
For I := 0 to SingletonHash.Count - 1 do
Begin
TSingleton(SingletonHash.Objects[I]).BeforeDestroy;
End;
// free all singleton and InterfacedSingleton objects.
For I := 0 to SingletonHash.Count - 1 do
Begin
TSingleton(SingletonHash.Objects[I]).Dispose;
End;
End;
{ TSingleton }
Procedure TSingleton.BeforeDestroy;
Begin
End;
Procedure TSingleton.Dispose;
Begin
Inherited FreeInstance;
End;
Procedure TSingleton.FreeInstance;
Begin
//
End;
Procedure TSingleton.Init;
Begin
End;
class function TSingleton.NewInstance: TObject;
Var
Singleton: TSingleton;
Begin
If SingletonHash = Nil then
SingletonHash := TStringList.Create;
If SingletonHash.IndexOf(Self.ClassName) = -1 then
Begin
Singleton := TSingleton(Inherited NewInstance);
Try
Singleton.Init;
SingletonHash.AddObject(Self.ClassName, singleton);
Except
Singleton.Dispose;
Raise;
End;
End;
Result :=
SingletonHash.Objects[SingletonHash.IndexOf(Self.ClassName)] as TSingleton;
End;
Initialization
SingletonHash := Nil;
Finalization
If SingletonHash <> Nil then
ClearSingletons;
SingletonHash.Free;
End.
|
|
| Back to top |
|
 |
Trevor de Koekkoek Guest
|
Posted: Wed Dec 31, 2003 6:01 pm Post subject: Re: Singleton - Another way. |
|
|
Forgive me if I've missed the obvious, I'm just jumping into this newsgroup,
but I have a question: Why do you need a hash table (or TStringList in this
case)? Isn't it always going to contain only 1 object?
-Trevor
"Yoav" <yoav (AT) tsoft-tele (DOT) com> wrote
| Quote: | Hi Andrea,
If SingletonHash.IndexOf(Self.ClassName) = -1 then
Begin
Singleton := TSingleton(Inherited NewInstance);
Try
Singleton.Init;
SingletonHash.AddObject(Self.ClassName, singleton);
Except
Singleton.Dispose;
Raise;
End;
End;
Result :=
SingletonHash.Objects[SingletonHash.IndexOf(Self.ClassName)] as
TSingleton;
End;
|
|
|
| Back to top |
|
 |
Yoav Guest
|
Posted: Thu Jan 01, 2004 10:11 am Post subject: Re: Singleton - Another way. |
|
|
Trevor de Koekkoek wrote:
| Quote: | Forgive me if I've missed the obvious, I'm just jumping into this newsgroup,
but I have a question: Why do you need a hash table (or TStringList in this
case)? Isn't it always going to contain only 1 object?
|
The reason is very simple. This TSingleton class is a base class, that
any derived class is itself a singleton. If you derive A and B from
TSingleton, both A and B will be singletons, and you will be able to
construct one instance of each (a total of two instances).
The Hash table is needed to manage this list of derived classes.
In this code, I have replaced the hash table with a string list because
there is no standard hash table in Delphi 6, so I had to replace the one
I'm using with a standard object.
| Quote: | -Trevor
"Yoav" <yoav (AT) tsoft-tele (DOT) com> wrote in message
news:3fef10dd (AT) newsgroups (DOT) borland.com...
Hi Andrea,
If SingletonHash.IndexOf(Self.ClassName) = -1 then
Begin
Singleton := TSingleton(Inherited NewInstance);
Try
Singleton.Init;
SingletonHash.AddObject(Self.ClassName, singleton);
Except
Singleton.Dispose;
Raise;
End;
End;
Result :=
SingletonHash.Objects[SingletonHash.IndexOf(Self.ClassName)] as
TSingleton;
End;
|
|
|
| Back to top |
|
 |
Bryan Crotaz Guest
|
Posted: Thu Jan 01, 2004 1:49 pm Post subject: Re: Singleton - Another way. |
|
|
Use Find rather than IndexOf - it's a binary search. Also need to make the
stringlist sorted.
Bryan
"Yoav" <yoav (AT) tsoft-tele (DOT) com> wrote
| Quote: | Trevor de Koekkoek wrote:
Forgive me if I've missed the obvious, I'm just jumping into this
newsgroup,
but I have a question: Why do you need a hash table (or TStringList in
this
case)? Isn't it always going to contain only 1 object?
The reason is very simple. This TSingleton class is a base class, that
any derived class is itself a singleton. If you derive A and B from
TSingleton, both A and B will be singletons, and you will be able to
construct one instance of each (a total of two instances).
The Hash table is needed to manage this list of derived classes.
In this code, I have replaced the hash table with a string list because
there is no standard hash table in Delphi 6, so I had to replace the one
I'm using with a standard object.
-Trevor
"Yoav" <yoav (AT) tsoft-tele (DOT) com> wrote in message
news:3fef10dd (AT) newsgroups (DOT) borland.com...
Hi Andrea,
If SingletonHash.IndexOf(Self.ClassName) = -1 then
Begin
Singleton := TSingleton(Inherited NewInstance);
Try
Singleton.Init;
SingletonHash.AddObject(Self.ClassName, singleton);
Except
Singleton.Dispose;
Raise;
End;
End;
Result :=
SingletonHash.Objects[SingletonHash.IndexOf(Self.ClassName)] as
TSingleton;
End;
|
|
|
| Back to top |
|
 |
Larry Siemer Guest
|
Posted: Thu Jan 01, 2004 3:01 pm Post subject: Re: Singleton - Another way. |
|
|
| Quote: | In this code, I have replaced the hash table with a string list
because
there is no standard hash table in Delphi 6, so I had to replace the
one
I'm using with a standard object.
|
In D6 and D7, IniFiles.pas has a class called THashedStringList. It's
description says: 'A TStringList that uses TStringHash to improve the
speed of Find'.
|
|
| Back to top |
|
 |
Wayne Niddery [TeamB] Guest
|
Posted: Thu Jan 01, 2004 7:18 pm Post subject: Re: Singleton - Another way. |
|
|
Bryan Crotaz wrote:
| Quote: | Use Find rather than IndexOf - it's a binary search. Also need to
make the stringlist sorted.
|
If the Sorted property is true, IndexOf simply calls Find. But it saves a
procedure call.
--
Wayne Niddery - Logic Fundamentals, Inc. (www.logicfundamentals.com)
RADBooks: http://www.logicfundamentals.com/RADBooks.html
"It is error alone which needs the support of government. Truth can
stand by itself." - Thomas Jefferson
|
|
| Back to top |
|
 |
Trevor de Koekkoek Guest
|
Posted: Fri Jan 02, 2004 5:04 pm Post subject: Re: Singleton - Another way. |
|
|
| Quote: | The Hash table is needed to manage this list of derived classes.
|
I don't see why this would be necessary. A singleton maintains its own
reference. You shouldn't need to keep track of the other instances.
-Trevor
"Yoav" <yoav (AT) tsoft-tele (DOT) com> wrote
| Quote: | Trevor de Koekkoek wrote:
Forgive me if I've missed the obvious, I'm just jumping into this
newsgroup,
but I have a question: Why do you need a hash table (or TStringList in
this
case)? Isn't it always going to contain only 1 object?
The reason is very simple. This TSingleton class is a base class, that
any derived class is itself a singleton. If you derive A and B from
TSingleton, both A and B will be singletons, and you will be able to
construct one instance of each (a total of two instances).
The Hash table is needed to manage this list of derived classes.
In this code, I have replaced the hash table with a string list because
there is no standard hash table in Delphi 6, so I had to replace the one
I'm using with a standard object.
-Trevor
"Yoav" <yoav (AT) tsoft-tele (DOT) com> wrote in message
news:3fef10dd (AT) newsgroups (DOT) borland.com...
Hi Andrea,
If SingletonHash.IndexOf(Self.ClassName) = -1 then
Begin
Singleton := TSingleton(Inherited NewInstance);
Try
Singleton.Init;
SingletonHash.AddObject(Self.ClassName, singleton);
Except
Singleton.Dispose;
Raise;
End;
End;
Result :=
SingletonHash.Objects[SingletonHash.IndexOf(Self.ClassName)] as
TSingleton;
End;
|
|
|
| Back to top |
|
 |
Joanna Carter (TeamB) Guest
|
Posted: Fri Jan 02, 2004 9:54 pm Post subject: Re: Singleton - Another way. |
|
|
Trevor de Koekkoek wrote:
| Quote: | I don't see why this would be necessary. A singleton maintains its
own reference. You shouldn't need to keep track of the other
instances.
|
The technique described is an attempt at allowing people to derive any class
that requires Singleton behaviour from a base TSingleton class.
The list is there because, in this situation, you would need to keep a
reference to the single instance of any of the derived classes.
Personally, I would not use this technique as this then forces you to derive
all classes that have Singleton behaviour from this one class; this would
then mean that you could not make a TForm or such derivative a singleton.
Better to implement the Singleton behaviour in each class it is required.
Joanna
--
Joanna Carter (TeamB)
Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker
|
|
| Back to top |
|
 |
Trevor de Koekkoek Guest
|
Posted: Sat Jan 03, 2004 11:23 pm Post subject: Re: Singleton - Another way. |
|
|
| Quote: | Personally, I would not use this technique as this then forces you to
derive
all classes that have Singleton behaviour from this one class; this would
then mean that you could not make a TForm or such derivative a singleton.
|
I would agree Joanna. I guess I've been working too much with Java and C#
where you can have static variables, which would make keeping this list
unnecessary. The thing that bothers me about this this technique is that it
just "feels" wrong. One singleton should not need to have any knowledge
about another one. But again I agree with your sentiments. Implementing a
singleton each time is preferrable and is only a few lines of code.
-Trevor
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|