Re: Delphi TObjectlist


Posted by webmaster Guido
In Reply to: Delphi TObjectlist posted by Veerle Ruijgers:

: can somebody help me with some issues with a TobjectList ?
:
: What is important is that I can keep a position in the list, because it's about a game (school project) and that position corresponds with a position on a playboard. So I store all the objects of the playbord in an TObjectlist.
:
: 1.How can I retrieve properties and use methods of the objects in the objectlist on that specific position ? Can I directly do that in a way or do I need to retrieve the object out the list or something ?
: 2. How can I replace an object on a specific position ? (without changing any other positions)
:
: PS. using an 2dim array would propably more easy but my teacher has something with lists...
-----------------

A TObjectList is capable of storing a list of objects (did not exist before Delphi 5). You mainly use it when you don't know how many objects will be stored in the list. These can be objects of your own design, for example of type TGameObject, but you can add also Delphi objects such as TStringList or even components. You may freely mix different types of objects, but for the following examples, let's stick with all objects of the same type.

Say you want to have a list called "GameList". Because it will be used in more than one procedure, you have to declare GameList outside of any procedure. The same goes for the variable that you want for keeping a position, say "GamePos". If you plan to use these two variables only in one unit, then you can declare them in the "private" section of the form, like this:

type
  TForm1 = class(TForm)
    Label1: TLabel;
    ...
    ...
  private
    { Private declarations }
    GameList: TObjectList; // list that contains TGameObjects
    GamePos: integer; // current position in the game
  public
    { Public declarations }
  end;

(Note: if you want these two variables two be also available in other unit(s), you should declare them under "public" instead of under "private")

Let's create GameList when the main form is created:

procedure TForm1.FormCreate(Sender: TObject);
begin
  GameList := TObjectList.Create(True); 
end;

Because you must destroy every object that you created yourself, let's destroy GameList at the end of the program, when the main form is destroyed:

procedure TForm1.FormDestroy(Sender: TObject);
begin
  GameList.Free; 
  // Note: the objects of the list are destroyed automatically, because
  // the list was created with .Create(TRUE)
  // If we created the list with .Create(FALSE) we would have to free
  // the items one by one ourselves, before freeing the list.
end;

Note: before Delphi 5, you had to use a TList instead of a TObjectList. You had to destroy *yourself* all the objects that you placed in the TList, before destroying the TList. A TList doesn't free its items automatically.

This is how you create an object, set its properties and add it to the list:

procedure TForm1.SomeProcedure;
var
  GameObject: TGameObject;
begin
  ...
  GameObject := TGameObject.Create; 
  GameObject.Points := 0;
  GameObject.Name := 'Julie';
  GameList.Add(GameObject);
  ...
end;

But of course, the class TGameObject must have been declared somewhere.
Let's declare it in the same unit. In the interface section, under type and before TForm1 = class(TForm), add:

TGameObject = class(TObject)
  public
    Points: integer;
    Name: string;
    constructor Create;
  end;

(Note: this is a very basic declaration. In a real application, you would have your code in several sections, such as private, public and published. But don't worry for now :) )

At the beginning of the implementation section, add these lines:

implementation

constructor TGameObject.Create;
begin
  inherited; // call the parent Create method
  // set defaults
  Points := 0;
  Name := '';
end;

There is a disadvantage to TObjectList over a "fixed" array: when you write GameList[N], then you get only a "generic" object, in other words: a value of the type TObject, not a TGameObject! For example, you are not allowed to write the following:

  P := GameList[3].Points;

...because a generic TObject does not have a property "Points". So, in order to properly address an item in your list, "type casting" is required. Type casting is code that says: look at this "generic" object AS an object of the type "TypeSoAndSo", for example:

  TGameObject(GameList[N])
means "item number N of GameList, seen AS a TGameObject".

Attention: numbering starts at 0, so the first object that you have added to the list is GameList[0], the second is GameList[1], and so on...

Let's assume that you updated variable GamePos continuously during the game; it contains an integer value somewhere from 0 to maximally the "number of objects minus one". At a certain moment you need some properties of the game-object that corresponds with the current game position:

procedure TForm1.OtherProcedure;
var
  GameObject: TGameObject;
  P: integer;
begin
  GameObject := TGameObject(GameList[GamePos]);  
  P := GameObject.Points;
  ...
end;

Replacing an object by another one, without changing anything else in the list, is very simple. For example, to replace the object at the "current gameposition" with another game-object:

procedure TForm1.ReplaceGame;
var
  OtherGameObject: TGameObject;
begin
  ....
  GameList[GamePos] := OtherGameObject;
  ...
end;

Other example: replacing the object at position Pos1 with the object at position Pos2:

  GameList[Pos1] := GameList[Pos2];

Attention: in both these replace examples, the object that *originally* was in the list, before replacing it with another one, is destroyed (freed) automatically if the TObjectList's property "OwnsObjects" is True. If you use a TList instead of a TObjectList, then you must free the old object yourselve *before* replacing it, otherwise you'll have serious "memory leaks" in your application.


[ DelphiLand FAQ ] [ Delphi Tutorials ]