 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Bill N Guest
|
Posted: Thu Nov 06, 2003 4:31 pm Post subject: refering to objects in a TList--must be a better way |
|
|
I have created three classes (simplified fictious classes): TArticles,
TTitle,TSubTitle
TArticles=class
private
FName: string;
FTitles: TList;
procedure SetTitle(const Value: string);
public
constructor Create;
destructor Destroy;
property Name:string read FName write SetName;
property Titles:TList read FTitles;
end;
TTitle=class
private
FTitle: string;
FSubs: TList;
procedure SetTitle(const Value: string);
public
constructor Create;
destructor Destroy;
property Title:string read FTitle write SetTitle;
property Subs:TList read FDivSubs;
end;
TSubTitle=class
private
FSubTitle: string;
FText: TStrings;
procedure SetSubTitle(const Value: string);
public
constructor Create;
destructor Destroy;
property Title:string read FTitle write SetTitle;
property Text:TStrings read FText Write SetText;
end;
The problem is if I create a TArticles object and try to refer to the
Text property I'm writing code like this:
======================================================================
var sl : TStringList;
Articles : TArticles;
begin
Articles:=TArticles.Create;
sl:=TStringList.Create;
sl.AddStrings(TSubTitle(TTitle(Title.Items[0]).Subs.Items[0]).Text);
end;
======================================================================
There's gotta be a better way of doing this?
Any help would be appreciated?
Thanks,
Bill N
Programmer/Systems Analyst
www.2rs.ca
|
|
| Back to top |
|
 |
Eric Hill Guest
|
Posted: Thu Nov 06, 2003 4:59 pm Post subject: Re: refering to objects in a TList--must be a better way |
|
|
| Quote: | I have created three classes (simplified fictious classes): TArticles,
TTitle,TSubTitle
|
Probably the easiest thing to do is to build your three classes as list
types themselves. Look for "type-safe lists" in google. I believe there
are also several on CodeCentral.
Basically, instead of a generic TList property, you build type-safe lists
for each type. Something like:
TArticle = class(TObject)
public
property Title: string read...write...;
property IDNumber: Integer read...write...;
end;
TArticleList = class(TObject)
private
function GetArticle(AIndex: Integer): TArticle;
procedure SetArticle(AIndex: Integer; const Value: TArticle);
public
property Item[AIndex: Integer]: TArticle read GetArticle write
SetArticle; default;
end;
Get the idea?
Eric
|
|
| Back to top |
|
 |
Nathanial Woolls Guest
|
Posted: Thu Nov 06, 2003 5:25 pm Post subject: Re: refering to objects in a TList--must be a better way |
|
|
| Quote: | Basically, instead of a generic TList property, you build type-safe lists
for each type. Something like:
|
To build on Eric's explanation, below is a full, type-safe list
implementation of your TArticle type. It's pretty easy to design something
to generate this code for you, as the only thing that changes is the type
(TArticle) and the instance name (Article):
interface
uses Classes, contnrs;
type
TArticleList = class(TObject)
private
{ Private declarations }
FList: TObjectList;
function GetCount: Integer;
function GetCapacity: Integer;
procedure SetCapacity(const Value: Integer);
function GetArticle(Index: Integer): TArticle;
procedure SetArticle(Index: Integer; const Value: TArticle);
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create; virtual;
destructor Destroy; override;
function Add: TArticle; overload;
procedure Add(const Article: TArticle); overload;
property Capacity: Integer read GetCapacity write SetCapacity;
property Count: Integer read GetCount;
procedure Clear;
procedure Delete(const Index: Integer);
function IndexOf(const Article: TArticle): Integer; overload;
procedure Remove(const Article: TArticle);
property Article[Index: Integer]: TArticle read GetArticle write
SetArticle; default;
published
{ Published declarations }
end;
implementation
uses SysUtils;
{ TArticleList }
procedure TArticleList.Add(const Article: TArticle);
begin
FList.Add(Article);
end;
function TArticleList.Add: TArticle;
begin
Result := TArticle.Create;
FList.Add(Result);
end;
procedure TArticleList.Clear;
begin
FList.Clear;
end;
constructor TArticleList.Create;
begin
FList := TObjectList.Create;
end;
procedure TArticleList.Delete(const Index: Integer);
begin
FList.Delete(Index);
end;
destructor TArticleList.Destroy;
begin
FList.Free;
inherited;
end;
function TArticleList.GetCount: Integer;
begin
Result := FList.Count;
end;
function TArticleList.GetCapacity: Integer;
begin
Result := FList.Capacity;
end;
function TArticleList.GetArticle(Index: Integer): TArticle;
begin
Result := TArticle(FList[Index]);
end;
function TArticleList.IndexOf(const Article: TArticle): Integer;
begin
Result := FList.IndexOf(Article);
end;
procedure TArticleList.Remove(const Article: TArticle);
begin
FList.Remove(Article);
end;
procedure TArticleList.SetCapacity(const Value: Integer);
begin
FList.Capacity := Value;
end;
procedure TArticleList.SetArticle(Index: Integer; const Value: TArticle);
begin
FList[Index] := Value;
end;
end.
|
|
| Back to top |
|
 |
Shawn Oster Guest
|
Posted: Tue Nov 11, 2003 6:24 pm Post subject: Re: refering to objects in a TList--must be a better way |
|
|
Nathanial,
Did you use a code-generator for this list or is it something you cobbled
together? I'd be interested in what you're using to generate it if it is a
tool. Also I noticed that you have the IndexOf method marked as overload
yet there is no other overloaded version in the class. Is that by design or
did you pull a method out for posting?
Thanks,
Shawn
"Nathanial Woolls" <nwoolls (AT) maine (DOT) rr.com> wrote
| Quote: | Basically, instead of a generic TList property, you build type-safe
lists
for each type. Something like:
To build on Eric's explanation, below is a full, type-safe list
implementation of your TArticle type. It's pretty easy to design
something
to generate this code for you, as the only thing that changes is the type
(TArticle) and the instance name (Article):
snip/ |
|
|
| Back to top |
|
 |
David Guest
|
Posted: Wed Nov 19, 2003 2:30 am Post subject: question about function and procedure Add... |
|
|
| Quote: |
procedure TArticleList.Add(const Article: TArticle);
begin
FList.Add(Article);
end;
function TArticleList.Add: TArticle;
begin
Result := TArticle.Create;
FList.Add(Result);
end;
Sorry, I can't see the purpose of the function .add. Clues for me? |
Also, when loading the list from a database I create a variable of type
TArticle and then use the procedure Add. Is this the 'right' way to do
this?
Thanks
David
|
|
| Back to top |
|
 |
Jim Cooper Guest
|
Posted: Wed Nov 19, 2003 9:51 am Post subject: Re: question about function and procedure Add... |
|
|
| Quote: | Sorry, I can't see the purpose of the function .add. Clues for me?
|
It just saves you the extra step of creating the new object that was
added. TCollection works like that, for instance.
| Quote: | Is this the 'right' way to do this?
|
It's matter of taste. It saves a line of code to use the function,
that's all. Use the way that seems most sensible to you (and whoever
else is working on the code).
Cheers,
Jim Cooper
____________________________________________
Jim Cooper [email]jcooper (AT) tabdee (DOT) ltd.uk[/email]
Tabdee Ltd http://www.tabdee.ltd.uk
TurboSync - Connecting Delphi with your Palm
____________________________________________
|
|
| Back to top |
|
 |
David Guest
|
Posted: Thu Nov 20, 2003 12:52 am Post subject: 2 more questions about this example |
|
|
Hi
I am using Nathanial's code, replacing Article with Product, so I have
TProduct and TProductList.
1) However, the following code produces rproduct.cpcode = '',
rproduct.prodname = '' and rproduct = '' at the point indicated.
This is just a sample, I need to load selected records from our 'product'
table into the list (<20).
cbproduct is a TComboBox.
2) in tproductlist.destroy we have flist.free; This line always produces an
application exception. Any ideas?
// in the formshow
rproductlist := tproductlist.create;
rproduct := tproduct.create;
try
rproduct.cpcode := 'Dave';
rproduct.prodname := 'Dave';
rproduct.odbc_name := 'Dave';
rproductlist.add(rproduct);
rproduct.clear_one; // blanks all the fields.
indx := 0;
imax := rproductlist.Count;
while indx < imax do
begin
rproduct := rproductlist.product[indx]; // after running this line
..cpcode, .prodname and .odbc_name are ''
cbproduct.items.add(rproduct.prodname);
inc(indx);
end;
finally
rproduct.free;
end;
// rproductlist.free is in the .onclose
Note: In the past I would have used a string grid for this, quite
successfully. However, Nathaniel's solution is much more flexible so I
would like to understand what I did wrong?
Many thanks
David
|
|
| Back to top |
|
 |
Harley Pebley Guest
|
Posted: Thu Nov 20, 2003 1:06 am Post subject: Re: 2 more questions about this example |
|
|
| Quote: | 1) However, the following code produces rproduct.cpcode = '',
rproduct.prodname = '' and rproduct = '' at the point indicated.
// in the formshow
rproductlist := tproductlist.create;
rproduct := tproduct.create;
try
rproduct.cpcode := 'Dave';
rproduct.prodname := 'Dave';
rproduct.odbc_name := 'Dave';
rproductlist.add(rproduct);
rproduct.clear_one; // blanks all the fields.
indx := 0;
imax := rproductlist.Count;
while indx < imax do
begin
rproduct := rproductlist.product[indx]; // after running this line
.cpcode, .prodname and .odbc_name are ''
cbproduct.items.add(rproduct.prodname);
inc(indx);
end;
finally
rproduct.free;
end;
// rproductlist.free is in the .onclose
|
You are creating a list and an object. Then you are putting data in the
object and adding that object to the list. Then you are clearing the
object. It's working as written. Remember, the object in the list is the
same as the local reference. You have two references to the same object,
not two different objects. What happens in one will show up when accessed
via the other reference.
| Quote: | 2) in tproductlist.destroy we have flist.free; This line always produces an
application exception. Any ideas?
|
I expect you meant rproductlist.free. Is the list an TObjectList
descendent? If so, OwnsObjects is defaults to true and it is trying to free
the objects in the list, but you've already freed it above. The AV is on
the second free call. This condition is known as a "stale pointer". You end
up with a reference to an object that doesn't exist.
HTH,
Harley Pebley
|
|
| Back to top |
|
 |
David Guest
|
Posted: Thu Nov 20, 2003 2:38 am Post subject: Thanks |
|
|
While I was a by-stander in this discussion, with some of my own questions,
I learnt a lot here.
A big thanks to everyone involved. Much appreciated.
David
|
|
| Back to top |
|
 |
Joanna Carter (TeamB) Guest
|
Posted: Thu Nov 20, 2003 7:57 am Post subject: Re: Thanks |
|
|
David wrote:
| Quote: | While I was a by-stander in this discussion, with some of my own
questions, I learnt a lot here.
|
Which discussion was that?
Joanna
--
Joanna Carter (TeamB)
Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker
|
|
| Back to top |
|
 |
David Guest
|
Posted: Thu Nov 20, 2003 9:01 am Post subject: Re: Thanks |
|
|
| Quote: |
Which discussion was that?
Joanna
|
The gentlemen in this thread were discussing using TObjectList and proposed
a way by which it could be used (which I understood)
David.
|
|
| 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
|
|