Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Using collections 5

Status
Not open for further replies.

ByzantianX

Programmer
Dec 18, 2000
103
I would to find out is it (I guess it is) and how it is possible to use collections, for example, of objects or records (structures). What I would like to do is to define a class of record type, then to instantiate several records and to manipulate them over the collection (to add, count, remove etc.). Could anyone help me with some small code example or something (I was using VB for years, and there, it's quite simple; although Delphi is much more efficient environment in general than VB).Thanks in advance!
 
The TObjectList is probably what you are looking for.

[blue]
Code:
type
  TScheduleRecord = class(TObject)
    repkey:integer;
    StartDate:TDateTime;
    routekey:integer;
    :
    :
  end;

  TDM1 = class(TDataModule)
    procedure DataModuleCreate(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
  private
    { Private declarations }
    FActiveRepKey:integer;
    FActiveRepName:string;
    ScheduleDB:TObjectList;
    procedure PopulateScheduleDB;
    :
    :
  end;

procedure TDM1.DataModuleCreate(Sender: TObject);
begin
  ScheduleDB := TObjectList.Create;
  :
  :
  PopulateAvailableReps;
end;

procedure TDM1.DataModuleDestroy(Sender: TObject);
begin
  ScheduleDB.Free;
  :
  :
end;

procedure TDM1.PopulateScheduleDB;
var
  fInput: TextFile;
  sBuffer:string;
  ARecord:TScheduleRecord;
  :
  :
begin
  ARecord := TScheduleRecord.Create;
  ARecord.repkey := 123;
  ARecord.StartDate := StrToDateTime('05/05/03');
  ARecord.routekey := 4567;
    :
    :
  ScheduleDB.Add( ARecord );
end;
[/color]

Note that even though the variable ARecord is lost once the procedure ends, the memory is still allocated and the pointer is in the list. If you keep the default setting, the individual list members (records) will be freed automatically when you free the list.

Check the help file for TObjectList for the methods and properties available.
 
The TList class probably gives you the facilities that you require. The following code fragments should give you the basis of how to use TList. I haven't tested any of them so there may be some typos.
Code:
type
MyRec = record
 field1: string;
 field2: integer;
end;
...
var
 m1, m2, m3: MyRec;
 MyList: TList;
...
begin
// Add code to set up values in m1, m2, m3 
 MyList := TList.Create;
 try
  MyList.Add ( m1 );
  MyList.Add ( m2 );
  MyList.Add ( m3 );
  ShowMessage ( IntToStr ( MyList.Count ) );
  MyList.Delete ( 1 );  // Remove 2nd item
  ShowMessage ( IntToStr ( MyList.Count ) );
 finally
  MyList.Free;
 end;
end;

Have a look at the Delphi Help for TList. TList is a useful component.

Andrew
 
Thank you, both Zathras and Towerbase, it's been really helpful (and it's exactly what I need)!
 
Yes it is possible and it works well. Delphi help on doing this is somewhat thin, but I took the plunge a few weeks ago and found the exercise fruitful.

You need to subclass TCollection and TCollectionItem. By convention the collection has the classname of the item with an "s" on the end, e.g. TField and TFields. I guess you've already worked that out.

The trick is knowing which methods you must override to get the collection mechanism working. I think the list is:

TCollectionItem
GetDisplayName (not vital, but very useful)
Assign (Probably should, but I didn't bother)

TCollection
Items / GetItem / SetItem (Not an override, but create a property that gets and sets your new item class

I looked at one of the examples in the Delphi source. Naturally you will have lots more properties and methods, but I think that the ones above are the only one that you need to have in order to the the collection/collectionitem pair working.

Have fun
Simon
 
For specialised collections, you have builtIn objects (like TStringList). But for more control i advise you to use the TList object (from where all the specialised collections are derived).

The main advantage is that TList stores pointers to objects and therefore you can insert as many objects of different types that you want. It allows you to add, delete, count objects.

For example let's say you create a class called MyObj
Code:
type MyObj = class
   attribute1 : integer;
   attribute2 : string;
   procedure proc1();
   function  func1() : integer;
end;

every object you create automatically inherits delphi's TObject object. this includes freeing memory after use, storing class name and so on...

now you can either create collection a class that extends the TList object or you can directly use TList. let's take the first case (because by deriving TList you get to add attributes, functions and procedures that you need in addition to those of TList):
Code:
type MyObjCollection = class (TList)
      collectionAttr1 : integer;
      collectionAttr2 : string;
  ...so on...
      constructor Create();
      function AddObj(obj : MyObj) : boolean;
      function getObjWithAttr2(value : string) : TList;
end;
TList has builtIn procedures for adding, inserting, deleting, counting element. but if you need to apply modifications to the objects you include, you could create a procedure that first does all this then calls TList's add method.
The second function (getObjWithAttr2(value : string) : TList;) could be used to return a list only with the objects that have attribute2 equal to the value parameter.(just an example).

Now let's take a look at the implementation part:
Code:
implementation

constructor MyObjCollection.Create();
begin
     // set the default values of the collection
     self.collectionAttr1 := 0;
     self.collectionAttr2 := '';
end;

function MyObjCollection.AddObj(obj : MyObj) : boolean;
var
ok : boolean;
begin
  result := false;
  ok := false;
  //do checking procedure (let's say you need the obj to satisfy certain conditions before adding it to the collection). if it meets the conditions then ok := true;
   if ok then
   begin
     self.add(obj);
     result := true;
  end;
end;

function MyObjCollection.getObjWithAttr2(value : string) : TList;
var
resList : TList;
i : integer;
begin
   // we create a new TList to contain the objects we have to return
   resList := TList.Create();
   resList.Clear;

   for i:=0 to self.Count-1 do
   begin
       //now we call the object stored at position i in the list. notice that you need to make a casting since the list only contains pointer addresses of the objects stored within
       if MyObj(self.Items[i]).attribute2 = value then resList.Add(MyObj(self.Items[i]));
   end;
   result := resList;
end;

now that you defined the two classes you can start working with them. in a function you could write:
Code:
procedure startUsingClasses();
var
objCollection : MyObjCollection;
tempObj : MyObj;
i : integer;
begin
    // you allocate memory for the collection
    objCollection := MyObjCollection.Create;
    for i:=0 to 10 do
    begin
       // you allocate memory for the object
       tempObj := MyObj.Create;
       // assign values to object's attributes
       tempObj.attribute1 := i;  
       tempObj.attribute2 := '';  
       // and finally add it to the collection
       if not objCollection.AddObj(tempObj) then Showmessage('obj number ' + intToStr(i) + ' could not be added to the collection');
    end;

    // to access attribute1 of an element of the collection you would write
    MyObj(objCollection.items[i]).attribute1
end;

from here on, the posibilities are unlimmited. you can create your own constructors, destructors, functions and procedures for your objects (of various types) as well as collections and use them in combination.

I hope this gave you a hint on how to work with collections.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top