Home

The TList Collection Class

   

TList Fundamentals

 

Introduction

 

The TStrings class is used to create a list of single items, such as a list of names or a list of numbers. Sometimes you will want a list that itself is made of objects, an object in this sense being made of its own properties.

   

The Visual Component Library provides various classes adapted for creating a list of objects. As you know, such objects are made of internal parts; for example a car is made of doors, tires, and options (air condition, power steering, cruise control, etc) while a house is made of rooms, furniture, books, electronic devices, etc.

To support the ability to create a list of objects, the VCL provides a class named TList.

Before creating the actual list of objects, you should first define the kind of object will make up the list. One way to do this is to create a class that holds the members or characteristics of the object. For example, for a list of countries, each object can include the country name, its area, its population, its capital, its internet code, etc. The object can be created as follows:

//---------------------------------------------------------------------------
#ifndef CountryH
#define CountryH
#include <vcl.h>
//---------------------------------------------------------------------------
class TCountry
{
public:
    UnicodeString CountryName;
    double Area;
    long Population;
    UnicodeString Capital;
    UnicodeString InternetCode;
};
//---------------------------------------------------------------------------
#endif

Preparing a List

The TList class considers that an object is defined as

void *ObjectOfTheList[Index];

As you can see from this definition, TList does not specify what type of list you want to create as long as you can define it as an entity, an object. The second issue to keep in mind is that, because TList does not care about the kind of list you want to create and does not know in advance the number of objects in your list, it conveniently keeps the objects of your list in an array. This means that, as you create your list, TList adds your objects in an expanding list.

To initiate a VCL list, the first thing you must do is to declare an instance of a TList. If the list will be used as a local object, you can declare it in a function or event. If the list will be accessed by more than one event or function, you should declare its instance in the class that will host the list. Because TList is a VCL object, it must be declared as a pointer:

//---------------------------------------------------------------------------

#ifndef ExerciseH
#define ExerciseH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include "Country.h"
//---------------------------------------------------------------------------
class TfrmExercise : public TForm
{
__published:	// IDE-managed Components
private:	// User declarations
	TList * Countries;
public:		// User declarations
	__fastcall TfrmExercise(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

In the constructor or a method of the class that will host the list, initialize the pointer by letting the compiler know which class the list instance belongs to. This is done using the new operator. Here is an example:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Exercise.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmExercise *Form1;
//---------------------------------------------------------------------------
__fastcall TfrmExercise::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TfrmExercise::FormCreate(TObject *Sender)
{
	Countries = new TList;
}
//---------------------------------------------------------------------------

After using the class, you should (must) delete it and recover the memory it was using. This is done using the delete operator. If the list was created globally in a form's class, you can delete it in the OnDestroy event of the form. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TfrmExercise::FormDestroy(TObject *Sender)
{
	delete Countries;
	Countries = NULL;
}
//---------------------------------------------------------------------------

Adding an Object to a List

Once you have a class whose list you want to create, you can define each instance of the object and add the instance to the list. Because the objects are stored in an array, you would repeat this process for each object you want to include in the list. The TList class provides all the necessary operations you would need to perform on a list.

Before adding an object to a list, you must "fill" it up first. This can be done by providing a value for each member of the object. Because you are responsible for creating the object, you are also responsible for providing the right value for each member of the object. If you provide a wrong or invalid value, TList does not have any mechanism of checking the internal values of the object. Consequently, you can build the simplest object that contains only one or two members, or you can build the most complex object that resembles a chemical reaction. The choice is yours.

Once the object is complete or at least acceptable as far as its structure is defined, you can add it to the list. This can be taken care of by using the TList::Add() method. Its syntax is:

int __fastcall Add(void * Item);

The Item to add must be a recognizable and defined object. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TfrmExercise::btnAddClick(TObject *Sender)
{
	TCountry * Pays = new TCountry;

	Pays->CountryName = L"Ecuador";
	Pays->Area = 283561;
	Pays->Population = 14790608;
	Pays->Capital = L"Quito";
	Pays->InternetCode = L"ec";
	Countries->Add(Pays);
}
//---------------------------------------------------------------------------

The Number of Items in a List

TList has an internal mechanism of counting the objects that are added to its list. This count is stored in the Count property:

__property int Count = {read=FCount,write=SetCount};

Therefore, you can call it anytime to find out how many items exist in a list. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TfrmExercise::btnAddClick(TObject *Sender)
{
	TCountry * Pays = new TCountry;

	Pays->CountryName = L"Ecuador";
	Pays->Area = 283561;
	Pays->Population = 14790608;
	Pays->Capital = L"Quito";
	Pays->InternetCode = L"ec";
	Countries->Add(Pays);

	Pays = new TCountry;

	Pays->CountryName = L"Algeria";
	Pays->Area = 2381741;
	Pays->Population = 34586184;
	Pays->Capital = L"Algiers";
	Pays->InternetCode = L"dz";
	Countries->Add(Pays);

	Pays = new TCountry;

	Pays->CountryName = L"Portugal";
	Pays->Area = 92090;
	Pays->Population = 10735765;
	Pays->Capital = L"Lisbon";
	Pays->InternetCode = L"pt";
	Countries->Add(Pays);
}
//---------------------------------------------------------------------------
void __fastcall TfrmExercise::btnCountClick(TObject *Sender)
{
	ShowMessage(L"The list contains " +
		    IntToStr(Countries->Count) + L" items");
}
//---------------------------------------------------------------------------

After clicking the Add button followed by the Count button, this would produce:

Countries Statistics

When using the Add() method, if the Item argument is the first item to be added to the list, it would receive an index of 0 and the Count would be 1. When you add an object, the Count is incremented. The newly added object receives an index of Count-1. This means that there are two main actions the Add() method performs. First it adds an object at the end of the list because the additions of items are incremental. Second, it returns the index of the newly added object. Knowing this index, you can access a specific object in the list.

The Capacity of a List

The capcity of a list is it size in memory units. To support it, the TList class is equipped with a property named Capacity:

__property int Capacity = {read=FCapacity,write=SetCapacity};

The capacity serves two purposes. If you want to specify the amount of memory that must be allocated when the list is initiated, assign a value to the Capacity property. On the other hand, if you want to find out how much memory a list is using, get the value of the Capacity.

If at one time you think the capacity of a TList collection is not enough, you can increase. This is done using the Expand() method. It's index is:

Classes::TList * __fastcall Expand(void);
 
 
 

The Item of a List

The TList class is equipped with an indexed property named Items:

__property void * Items = {read=Get,write=Put};

In reality, the items of a TList collection are stored as an array. To let you access each item using its array-position, the TList class overloads the [] operator:

void * __fastcall operator [](int Index);

lection and it can be represented as of Items[]. The TList::Items property takes an index as an integer and returns the object that is stored at that index. Remember that the TList class doesn't define or control the type of object it holds and it can hold almost anything. Therefore, when accessing a member of the list, you must cast it to the type of your object. You do this using reinterpret_cast. The basic formula to follow is:

Variable = reinterpret_cast<Class *>(TList Variable...);

You can also use the Items member variable in a for loop to scan the list.

The First Item of a List

To get to the very first item in the list, you have two options. You can call the Items variable with an index of 0 as Items[0]. Alternatively, you can call the TList::First() method whose syntax is:

void * __fastcall First(void);

Here is an example of calling this method:

//---------------------------------------------------------------------------
void __fastcall TfrmExercise::btnAddClick(TObject *Sender)
{
	TCountry * Pays = new TCountry;

	Pays->CountryName = L"Ecuador";
	Pays->Area = 283561;
	Pays->Population = 14790608;
	Pays->Capital = L"Quito";
	Pays->InternetCode = L"ec";
	Countries->Add(Pays);

	Pays = new TCountry;

	Pays->CountryName = L"Algeria";
	Pays->Area = 2381741;
	Pays->Population = 34586184;
	Pays->Capital = L"Algiers";
	Pays->InternetCode = L"dz";
	Countries->Add(Pays);

	Pays = new TCountry;

	Pays->CountryName = L"Portugal";
	Pays->Area = 92090;
	Pays->Population = 10735765;
	Pays->Capital = L"Lisbon";
	Pays->InternetCode = L"pt";
	Countries->Add(Pays);
}
//---------------------------------------------------------------------------
void __fastcall TfrmExercise::btnFirstClick(TObject *Sender)
{
	TCountry * FirstCountry = reinterpret_cast<TCountry *>(Countries->First());
	ShowMessage(L"The first country in the list is " +
				FirstCountry->CountryName);
}
//---------------------------------------------------------------------------

After clicking the Add followed by the First buttons, this would produce:

Countries Statistics

The Last Item of a List

To access the last item of a TList collection, you can either call Items[TList::Count-1] or use the TList::Last() method. Its syntax is:

void * __fastcall Last(void);

Here is an example of calling this method:

//---------------------------------------------------------------------------
void __fastcall TfrmExercise::btnLastClick(TObject *Sender)
{
	TCountry * FirstCountry = reinterpret_cast<TCountry *>(Countries->Last());
	ShowMessage(L"The first country in the list is " +
				FirstCountry->CountryName);
}
//---------------------------------------------------------------------------

The Index of an Item

If there is an item in the list and you want to get its index, you can call the TList::IndexOf() method. Its syntax is:

int __fastcall IndexOf(void * Item);

To use the IndexOf() method, you must provide the item that you want to locate. If the item exists, this function returns the index of the item.

Routine Operations on a List

 

Introduction

Some of the common operations performed on items of a list consist of adding, inserting, deleting, or moving items to or from a list. All these operations are already provided by the TList class. The most you have to do is to adapt the class to your goal.

In the previous section of this lesson, we learned how to statically create a list. That is, we learned how you, the programmer, can create a list for the user. If you want the user to have more control on the list, you should provide the ability to add new items to a list or insert items.

 

Inserting an Item to a List

Besides the TList::Add() method used to add an item to a list, the TList class also allows you to insert an item inside the list. This operation is handled by the Insert() method. Its syntax is:

void __fastcall Insert(int Index, void *Item);

The first argument, Index, specifies the index that the new item will occupy after being added. Because the list of items is zero-based (since it is a C++ array), to add an item to the first position, specify Index as 0. In the same way, to add an item to the 3rd position, specify Index as 2. The Item argument is the item that you want to insert.

There are two main ways you would use the Insert() method. If you know the exact position where you want to insert an object, then supply the known index. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TfrmExercise::btnInsertClick(TObject *Sender)
{
	TCountry * Pais = new TCountry;

	Pais->CountryName = L"Mexico";
	Pais->Area =  1964375;
	Pais->Population = 112468855;
	Pais->Capital = L"Mexico City";
	Pais->InternetCode = L"mx";

	Countries->Insert(0, Pais);
}
//---------------------------------------------------------------------------

By contrast, you can use Insert() to insert a new item before or after one of your choice. To do this, you must first retrieve the index of the item that will succeed the one you want to add. This index would be used as a the Index argument.

Deleting an Item From a List

If you find out that your list includes an item you don't need, you can remove such an item from your list. The deletion of an item from a TList list can be handled by the Delete() method. Its syntax is:

void __fastcall Delete(int Index);

To process your request, this function needs the index of the item you want to delete. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TfrmExercise::btnDeleteClick(TObject *Sender)
{
	Countries->Delete(2);
}
//---------------------------------------------------------------------------

You can also get the index using the TList::Items[] member variable.

Removing an Item From a List

Besides the Delete() method, the TList class provides a method used to delete a record if you know the value of the record instead of its position. The method is TList::Remove() and its syntax is:

int __fastcall Remove(void *Item);

Instead of the index, the Remove method needs the item itself. If you supply an item that exists in the list, Remove() would delete it. If the operation is successful, Remove() returns the index the item had.

There are two significant differences between the Delete() and the Remove() methods:

  • Because Delete() takes the Index of the item you want to remove, if the index is valid, the operation would be successful and stop. In other words, Delete() only makes sure that the index corresponds to a valid item number in the list: Delete() does not look for it; it only checks that the index is found
  • Remove() looks for the Item you supply to it. If the item exists, Remove() deletes it. If more than one item matches the Item argument you supply, Remove() deletes the first item that matches Item

Clearing a List

Clearing a list consists of deleting all of its records in one step. This operation can be taken care of by the TList::Clear() method. Its syntax is:

void __fastcall Clear();

As you can see, there is no particular information this function needs. If the list is empty, the method would not do anything. If the list contains records, then all of them would be deleted. The only thing you might do is to warn the user especially if the records cannot be recovered.

 
 
   
 

Home Copyright © 2010-2011 FunctionX, Inc.