TObjectList: Como trabalhar com coleções de objetos no Delphi

Neste microexemplo você aprenderá a trabalhar com a classe TObjectList no Delphi. Trata-se de uma classe genérica por meio da qual podemos manter uma coleção de objetos, que são acessíveis posteriormente por um índice.

Neste exemplo utilizamos a classe TObjectList para lidar com uma coleção de objetos. Essa é uma classe genérica e funciona de forma semelhante à TList, porém ela se encarrega de liberar seus itens da memória quando é destruída. Isso evita o vazamento de memória (memory leak) em nossas aplicações, que ocorre quando itens adicionados à coleção não são liberados.

Para demonstrar o uso desse tipo de coleção criamos uma estrutura orientada a objetos na qual temos duas classes: TVenda e TVendaItem. Além disso temos um formulário para fazer a manipulação dos objetos dentro da nossa coleção. Esses elementos estão organizados em units, da seguinte forma:

Cada uma dessas classes será explicada mais adiante.

Classe TVenda

Nesta classe temos três propriedades: IDVenda (Integer), Data (TDateTime) e ListaVendaItem(TObjectList<TVendaItem>). Além disso, implementamos seu construtor, destrutor e o método AdicionarVendaItem.

Na unit uVenda, o primeiro ponto a ser observado é que referenciamos na seção uses a unit System.Generics.Collections, pois é nela que está declarada a classe TObjectList:

uses System.Generics.Collections, System.SysUtils, uVendaItem;

Note que também estamos referenciando a unit uVendaItem, na qual declaramos a classe TVendaItem, e a System.SysUtils, na qual encontra-se a função EncodeDate que será usada mais adiante.

Na sequência temos a definição da classe TVenda, como vemos abaixo:

01 TVenda = class 02 private 03 FIDVenda: Integer; 04 FData: TDateTime; 05 FListaVendaItem: TObjectList<TVendaItem>; 06 { private declarations } 07 protected 08 { protected declarations } 09 public 10 { public declarations } 11 property IDVenda: Integer read FIDVenda write FIDVenda; 12 property Data : TDateTime read FData write FData; 13 property ListaVendaItem: TObjectList<TVendaItem> read FListaVendaItem 14 write FListaVendaItem; 15 constructor Create; 16 destructor Destroy; override; 17 procedure AdicionarVendaItem(pProduto: String); 18 published 19 { published declarations } 20 end;

Linhas 3 a 5: Atributos privados que representam o id, a data e os itens da venda, respectivamente;

Linhas 11 a 14: Propriedades públicas que encapsulam o acesso aos atributos privados. Note que cada propriedade é responsável por ler e escrever valores em cada um dos atributos privados;

Linhas 15 e 16: Declaração do construtor e do destrutor da classe, respectivamente;

Linha 17: Declaração do método responsável por adicionar um novo item a essa venda.

O método AdicionarVendaItem é responsável por instanciar um objeto do tipo TVendaItem dentro da propriedade FListaVendaItem e preencher suas propriedades de forma estática, da seguinte forma:

01 procedure TVenda.AdicionarVendaItem(pProduto: String); 02 var 03 I: Integer; 04 begin 05 FListaVendaItem.Add(TVendaItem.Create); 06 I := FListaVendaItem.Count -1; 07 FListaVendaItem[I].IDVendaItem := I; 08 FListaVendaItem[I].IDVenda := FIDVenda; 09 FListaVendaItem[I].Produto := pProduto; 10 end;

Linha 3: Aqui declaramos uma variável que será responsável por controlar o índice do item que está sendo adicionado a coleção;

Linha 5: Utilizamos o método Add da coleção, passando para ele um novo objeto do tipo TVendaItem;

Linha 6: Nesta linha obtemos o índice do último item da coleção, ou seja, aquele que acabou de ser adicionado. Precisamos desse índice para referenciar esse objeto nas próximas linhas;

Linhas 7 a 9: Preenchemos o item recém-criado.

Mais abaixo, na implementação do método Create da classe TVenda, estamos atribuindo valores iniciais aos fields e também instanciando a nossa coleção de itens:

01 constructor TVenda.Create; 02 begin 03 inherited; 04 FIDVenda := 0; 05 FData := EncodeDate(1900,1,1); 06 FListaVendaItem := TObjectList<TVendaItem>.Create; 07 end;

Linha 3: Nesta linha garantimos que será executada uma chamada ao método Create da classe ancestral de TVenda, nesse caso TObject;

Linha 4: Atribuímos o valor 0 ao field FIDVenda;

Linha 5: Utilizando a função EncodeDate setamos um valor padrão para a data da nossa venda;

Linha 6: Neste momento estamos instanciando a nossa coleção de itens, para adicionarmos itens a ela posteriormente.

Por fim, na implementação do método Destroy da classe TVenda precisamos liberar a nossa coleção da memória e ela se encarrega de liberar todos os itens que contém:

01 destructor TVenda.Destroy; 02 begin 03 FreeAndNil(FListaVendaItem); 04 inherited; 05 end;

Linha 3: Nesta linha liberamos a nossa coleção da memória e consequentemente todos os seus itens;

Linha 4: Aqui garantimos que será executada uma chamada ao Destroy da classe ancestral de TVenda, ou seja, TObject.

Classe TVendaItem

A classe TVendaItem possui apenas três propriedades, a fim de simular de forma simplificada os itens e uma venda. Sua definição pode ser vista abaixo:

01 TVendaItem = class 02 private 03 FIDVendaItem: Integer; 04 FIDVenda: Integer; 05 FProduto: String; 06 { private declarations } 07 protected 08 { protected declarations } 09 public 10 { public declarations } 11 property IDVendaItem: Integer read FIDVendaItem write FIDVendaItem; 12 property IDVenda: Integer read FIDVenda write FIDVenda; 13 property Produto: string read FProduto write FProduto; 14 published 15 { published declarations } 16 end;

Linhas 3 a 5: atributos privados que representam o id do item, o id da venda e o nome do produto, respectivamente;

Linhas 11 a 13: propriedades públicas que encapsulam o acesso aos atributos privados. Note que cada propriedade é responsável por ler e escrever valores em cada um dos atributos privados.

Form TFrmListaObjetos

Neste formulário, cuja interface pode ser vista na Figura 1, usamos as classes definidas anteriormente para simular a criação de uma venda, a adição de itens e sua posterior listagem em um controle do tipo TMemo:

Figura 1. Layout do form principal

Na seção private desse form declaramos uma variável do tipo TVenda, da seguinte forma:

private Venda: TVenda;

Em seguida é necessário instanciar esse objeto, o que foi feito no construtor do form, para garantir que após o form ser criado já poderemos usar esse objeto normalmente:

procedure TFrmListaObjetos.FormCreate(Sender: TObject); begin Venda := TVenda.Create; end;

A partir daí já podemos preencher essa venda e inserir itens. Para isso utilizamos o evento OnClick do botão “Cadastrar Venda”:

procedure TFrmListaObjetos.BtnCadastrarVendaClick(Sender: TObject); 01 begin 02 Venda.IDVenda := 1; 03 Venda.Data := Now; 04 05 Venda.ListaVendaItem.Clear; 06 MmDadosVenda.Clear; 07 08 Venda.AdicionarVendaItem('Sony Vaio XR8472'); 09 Venda.AdicionarVendaItem('Dell Vostro'); 10 Venda.AdicionarVendaItem('HP I7'); 11 12 BtnListarVenda.Enabled := True; 13 BtnCadastrarVenda.Enabled := False; 14 end;

Linhas 2 e 3: Preenchemos as propriedades do objeto Venda;

Linhas 5 e 6: Limpamos a coleção de itens da venda e o memo;

Linhas 8 a 10: Adicionamos três itens à venda;

Linhas 12 e 13: Habilitamos o botão de listar dados da venda e desabilitamos o botão de cadastrar nova venda.

Na sequência utilizamos o botão “Listar Venda” para imprimir no memo os dados da venda e seus itens. Para isso alteramos seu evento OnClick, da seguinte forma:

01 procedure TFrmListaObjetos.BtnListarVendaClick(Sender: TObject); 02 var 03 VendaItem: TVendaItem; 04 begin 05 MmDadosVenda.Lines.Add('IDVenda: ' + IntToStr(Venda.IDVenda)); 06 MmDadosVenda.Lines.Add('Data: ' + FormatDateTime('dd/mm/yyyy', Venda.Data)); 07 08 MmDadosVenda.Lines.Add(''); 09 MmDadosVenda.Lines.Add('<<Lista de produtos>>'); 10 11 for VendaItem in Venda.ListaVendaItem do 12 MmDadosVenda.Lines.Add('Produto : ' + VendaItem.Produto); 13 14 BtnListarVenda.Enabled := False; 15 BtnCadastrarVenda.Enabled := True; 16 end;

Linhas 5 e 6: Adicionamos ao memo os dados do id e data da venda;

Linhas 8 e 9: Adicionamos ao memo duas linhas para separar os dados da venda dos seus itens;

Linhas 11 e 12: Percorremos os itens da venda usando um laço for e imprimimos no memo os dados de cada um;

Linhas 14 e 15: Desabilitamos o botão de listagem e habilitamos o botão de cadastrar venda.

Por fim, no método Destroy do form liberamos o objeto Venda da memória:

procedure TFrmListaObjetos.FormDestroy(Sender: TObject); begin FreeAndNil(Venda); end;
Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados