Free Pascal - Usando TList
Autor: Professor Carlos | Publicado: 2011-06-01T10:42:00-04:00

A classe TList é usada para gerenciar uma coleção de ponteiros, com a grande vantagem de ser dinâmica. Ela dispõe de métodos para fazer busca na lista e ordenar os elementos, entre outros. No exemplo abaixo fazemos uso de alguns desses métodos.


unit Unit1;

{$mode objfpc}{$H+}

interface

uses
&nbsp; Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;

type
&nbsp; TContato = class
&nbsp; &nbsp; private
&nbsp; &nbsp; &nbsp; NomeContato &nbsp; &nbsp; : String;
&nbsp; &nbsp; &nbsp; TelefoneContato : String;

&nbsp; &nbsp; public
&nbsp; &nbsp; &nbsp; property Nome : String
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; read NomeContato;
&nbsp; &nbsp; &nbsp; property Telefone : String
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; read TelefoneContato;

&nbsp; &nbsp; &nbsp; constructor Create(const pNomeContato &nbsp; &nbsp; &nbsp; : String;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;const pTelefoneContato &nbsp; : String);
&nbsp; end;

&nbsp; { TfrmTlist }

&nbsp; TfrmTlist = class(TForm)
&nbsp; &nbsp; Button1: TButton;
&nbsp; &nbsp; ListBox1: TListBox;
&nbsp; &nbsp; procedure Button1Click(Sender: TObject);
&nbsp; private
&nbsp; &nbsp; { private declarations }
&nbsp; &nbsp; Agenda : TList;

&nbsp; &nbsp; procedure MostraAgenda;
&nbsp; public
&nbsp; &nbsp; { public declarations }
&nbsp; end;

var
&nbsp; frmTlist: TfrmTlist;

implementation

{$R *.lfm}

constructor TContato.Create(const pNomeContato &nbsp; &nbsp; &nbsp;: String;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;const pTelefoneContato : String);
begin
&nbsp; self.NomeContato &nbsp; &nbsp; := pNomeContato;
&nbsp; self.TelefoneContato := pTelefoneContato;
end;

function comparaPorNome(Item1 : Pointer; Item2 : Pointer) : Integer;
var
&nbsp; contato1, contato2 : TContato;
begin
&nbsp; contato1 := TContato(Item1);
&nbsp; contato2 := TContato(Item2);

&nbsp; if &nbsp; &nbsp; &nbsp;contato1.Nome &gt; contato2.Nome
&nbsp; then Result := 1
&nbsp; else if contato1.Nome = contato2.Nome
&nbsp; then Result := 0
&nbsp; else Result := -1;
end;

procedure TfrmTlist.Button1Click(Sender: TObject);
var
&nbsp; contato : TContato;

begin
&nbsp; Agenda := TList.Create;

&nbsp; contato := TContato.Create('Nádia Alves', '3523-0001');
&nbsp; Agenda.Add(contato);
&nbsp; contato := TContato.Create('Célio Silva', '3524-0000');
&nbsp; Agenda.Add(contato);

&nbsp; Agenda.Add(TContato.Create('Hélio Costa', '3320-1000'));
&nbsp; Agenda.Add(TContato.Create('Aldo Sousa', '3321-0001'));

&nbsp; MostraAgenda;
&nbsp; ShowMessage('Ordenando pelo nome. Pressione OK');
&nbsp; Agenda.Sort(@comparaPorNome);

&nbsp; MostraAgenda;
&nbsp; ShowMessage('Inserindo novo contato. Pressione OK');
&nbsp; Agenda.Insert(2, TContato.Create('Luis Gonzaga', '3325-4000'));
&nbsp; MostraAgenda;
&nbsp; ShowMessage('Excluindo um contato. Pressione OK');
&nbsp; Agenda.Delete(4);
&nbsp; ShowMessage('Pressione OK');
&nbsp; Agenda.free;
end;

procedure TfrmTlist.MostraAgenda;
var
&nbsp; i : Integer;
begin
&nbsp; ListBox1.Items.Clear;
&nbsp; for i := 0 to Agenda.Count-1 do
&nbsp; begin
&nbsp; &nbsp; ListBox1.Items.Add(TContato(Agenda[i]).Nome+' - '+
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (TContato(Agenda[i]).Telefone));
&nbsp; end;
end;

end.


No exemplo criamos uma classe Contato que será usada para povoar um TList&nbsp;que denominamos Agenda. Um TListBox é usado para apresentar os dados do TList.
Nas linhas que vão de 74 a 95 é onde acontece tudo que pretendemos mostrar. Inicialmente o TList é criado. Em seguida, são criados vários objetos Contato, que são adicionados à Agenda utilizando o método Add(). Este método sempre adiciona um objeto no fim da lista.
Após isso chamamos o método MostraAgenda, que foi criado para visualizar os dados da Agenda no TListBox. Na linha 86 há uma chamada ao método Sort(), que recebe como argumento o método comparaPorNome(). Aqui cabe uma explicação mais detalhada.
A ordenação de uma lista de objetos não é uma coisa tão natural como ordenar números inteiros ou strings. Como sabemos um objeto tem vários campos e por isso precisamos definir qual o critério que será usado para decidir que um objeto A é maior, menor ou igual a um outro objeto B. Por este motivo o método Sort() deve receber como parâmetro uma variável procedural, ou seja, um método que estabelece o critério de ordenação.
Dessa forma, foi criado o método comparaPorNome(), que recebe os ponteiros dos dois objetos a serem comparados. Tal método deve retornar -1 se o primeiro objeto for menor que o segundo, 1 se for maior e 0 se forem iguais. No nosso exemplo definimos que dois Contatos são iguais quando tem nomes iguais. Leia mais sobre variáveis procedurais no post Free Pascal - Variáveis Procedurais. Deve-se ressaltar que o Free Pascal define apenas como deve ser a assinatura do método que ele espera receber em Sort(). A implementação cabe ao desenvolvedor.
Na linha 90 um novo objeto é inserido na posição 2 do TList. Note que a primeira posição é 0.
Usamos o método Delete() para deletar um objeto em uma determinada posição. Na linha 93 excluímos o objeto da posição 4.
Quando a TList não é mais necessária, liberamos a memória usada chamando Free. Para criar uma lista de strings prefira usar TStrings ou sua descendente TStringList.