Olá galera, nesta Quick Tips mostrarei um componente no Delphi chamado TreeView. Veremos que neste componente não trabalhamos somente com textos adicionados a ele, formando aquela árvore, mas também adicionar um objeto inteiro, uma classe Cliente por exemplo, sendo o nó principal, e os telefones sendo seus nós filhos. Criaremos a aplicação e duas classes, sendo uma delas usando uma lista genérica, o famoso Generics, a partir do Delphi 2009.

Vamos ao exemplo! Adicione os itens a seguir, conforme a Figura 1:

  • 1 TreeView.
  • Cliente : 3 Bitbtns(BtnAdicionar, BtnEditar, BtnDeletar), 3 LabeledEdit(EdtCodigo, EdtNome, EdtCPF).
  • Telefone : 2 Bitbtns(BtnAddTelefone, BtnDelTelefone), 2 LabeledEdit(EdtDDD, EdtNumero) 1 Combobox(CbxTipo) e 1 Label.
Itens do formulário
Figura 1. Itens do formulário

Iremos criar agora uma nova Unit - salve a mesma como uTelefone.Esta class será bem simples, porém com ela poderemos ver um recurso muito poderoso englobado no Delphi 2009 em diante, chamado Generics. Utilize o código a seguir:


uTelefone
  
 unit uTelefone;
  
 interface
 Type
   TTelefone = Class
   private
     FDDD: String;
     FNumero: String;
     FTipo: String;
     procedure SetDDD(const Value: String);
     procedure SetNumero(const Value: String);
     procedure SetTipo(const Value: String);
   published
   public
     property DDD    : String read FDDD write SetDDD;
     property Numero : String read FNumero write SetNumero;
     property Tipo   : String read FTipo write SetTipo;
   End;
  
 implementation
  
 { TTelefone }
  
 procedure TTelefone.SetDDD(const Value: String);
 begin
   FDDD := Value;
 end;
  
 procedure TTelefone.SetNumero(const Value: String);
 begin
   FNumero := Value;
 end;
  
 procedure TTelefone.SetTipo(const Value: String);
 begin
   FTipo := Value;
 end;
  
 end.

Criaremos agora uma nova Unit e salve a mesma como uCliente.Nesta Unit observe que demos Uses em generics.defaults e generics.collections para podermos usar o Generics. Assim temos uma lista de Telefones para cada cliente, ou seja, um telefone pode ter um ou mais clientes. Com o código a seguir observe também que é bem simples excluir um telefone desta lista:


uCliente
  
 unit uCliente;
  
 interface
 uses generics.defaults, generics.collections, uTelefone;
 Type
   TCliente  = Class
   private
     FCodigo: Integer;
     FCPF: String;
     FNome: String;
     FTelefones: TList;
     procedure SetCodigo(const Value: Integer);
     procedure SetCPF(const Value: String);
     procedure SetNome(const Value: String);
     procedure SetTelefones(const Value: TList);
   published
   public
     Constructor Create;
     property Codigo   : Integer read FCodigo write SetCodigo;
     property Nome     : String read FNome write SetNome;
     property CPF      : String read FCPF write SetCPF;
     property Telefones: TList read FTelefones write SetTelefones;
   End;
  
 implementation
  
 { TCliente }
  
 constructor TCliente.Create;
 begin
   //Finalidade : Ao criar um Cliente já teremos a lista de telefones criadas
   Telefones := TList.Create; 
 end;
  
 procedure TCliente.SetCodigo(const Value: Integer);
 begin
   FCodigo := Value;
 end;
  
 procedure TCliente.SetCPF(const Value: String);
 begin
   FCPF := Value;
 end;
  
 procedure TCliente.SetNome(const Value: String);
 begin
   FNome := Value;
 end;
  
 procedure TCliente.SetTelefones(const Value: TList);
 begin
   FTelefones := Value;
 end;
  
 end.

Implementações no Form

A parte da manipulação do Cliente pode ser vista com o código a seguir:


    //Form : OnCreate
    //Form: onClose
    //Declare duas procedures, ClearCliente e ClearTelefone.

    procedure TFrmPrincipal.ClearCliente;
  begin
    {Finalidade : Limpar os Edits do Cliente}
    EdtCodigo.Clear;
    EdtNome.Clear;
    EdtCPF.Clear;
    EdtCodigo.SetFocus;
  end;

    procedure TFrmPrincipal.ClearTelefone;
  begin
    {Finalidade : Limpar os Edits e Combobox do Telefone}
    EdtDDD.Clear;
    EdtNumero.Clear;
    CbxTipo.ItemIndex := -1;
    EdtDDD.SetFocus;
  end;

    procedure TFrmPrincipal.FormCreate(Sender: TObject);
  begin
    TreeView1.HideSelection := False; //Destaca o item selecionado no ListView
  end;

procedure TFrmPrincipal.FormClose(Sender: TObject; var Action: TCloseAction);
var
  I: Integer;
  c: TCliente;
begin
  for I := 0 to TreeView1.Items.Count-1 do
  begin
    if TreeView1.Items[I].Level=0 then  
    //Exclui só a classe cliente que o resto será destruído, 
    com isso evitamos o erro de MemoryLeak.
    begin
      c:=TreeView1.Items[I].Data;
      c.Free;
    end;
  end;

end;


    //BtnAdicionar : OnClick
    //Finalidade : Criar um cliente, atribuir os valores a suas propriedades e logo
   // em seguida adicionarmos sua referência a TreeView
  procedure TFrmPrincipal.BtnAdicionarClick(Sender: TObject);
  Var
    Cliente : TCliente;
  begin
    Cliente := TCliente.Create;
   
    With Cliente do
    begin
      Codigo := StrToInt(EdtCodigo.Text);
      Nome   := EdtNome.Text;
      CPF    := EdtCPF.Text;
    end;
   
    TreeView1.Items.AddObject(Nil,Cliente.Nome,Cliente);
    ClearCliente;
  end;

    //BtnEditar : OnClick
    //Finalidade : Ao Carregar os dados podemos editar as informações de um Objeto 
   //selecionado, porém precisamos implementar
   //o método que irá carregar, vamos ver na última parte desta série de Quick Tips.
    procedure TFrmPrincipal.BtnEditarClick(Sender: TObject);
  begin
    if Assigned(TreeView1.Selected) then //Verifica se existe referencia no item selecionado
    begin
      TCliente(TreeView1.Selected.Data).Codigo := StrToInt( EdtCodigo.Text );
      TCliente(TreeView1.Selected.Data).Nome   := EdtNome.Text;
      TCliente(TreeView1.Selected.Data).CPF    := EdtCPF.Text;
      TreeView1.Selected.Text                  := EdtNome.Text;
    end;
  end;

    //BtnDeletar : OnClick
    //Finalidade : Excluir um Objeto Cliente da TreeView, e removendo a referencia
   
  procedure TFrmPrincipal.BtnDeletarClick(Sender: TObject);
  begin
    if Assigned(TreeView1.Selected) then 
    //Verifica se existe referencia no item selecionado
    begin
      if TreeView1.Selected.Level = 0 then
       //Verifica se estamos no primeiro nível para poder deletar
      begin
         TreeView1.Selected.Data := Nil;
         TreeView1.Items.Delete(TreeView1.Selected);
      end;
    end
    else
      ShowMessage('Nenhum item selecionado');
  end;

Já os códigos a seguir cuidam das implementações no Form: a parte da manipulação do Telefone e a recuperação dos dados no TreeView.


//BtnAddTelefone : OnClick
  //Finalidade : Adicionar um telefone ao cliente selecionado
  procedure TFrmPrincipal.BtnAddTelefoneClick(Sender: TObject);
 Var
   Node    : TTreeNode;
   Cliente : TCliente;
   Telefone : TTelefone;
 begin
   if Assigned(TreeView1.Selected) then
   begin
     if TreeView1.Selected.Level = 0 then //Verifica se estamos no primeiro Item
     begin
       Node     := TreeView1.Selected;
       Cliente  := TCliente(TreeView1.Selected.Data);
       Telefone := TTelefone.Create;
       With Telefone do
       begin
         DDD    := EdtDDD.Text;
         Numero := EdtNumero.Text;
         Tipo   := CbxTipo.Text;
       end; 

       Cliente.Telefones.Add(Telefone);
       TreeView1.Items.AddChildObject(Node,Telefone.Numero, Cliente);
       ClearTelefone;
     end
     else
       ShowMessage('Não trabalhamos com mais de um Nivel de Node');
   end
   else
     ShowMessage('Erro !!! Não existe um Node Pai Selecionado');
 end;


  //BtnDelTelefone :  OnClick
  //Finalidade : Excluir um telefone de um Cliente
  procedure TFrmPrincipal.BtnDelTelefoneClick(Sender: TObject);
 begin
   if Assigned(TreeView1.Selected) then
     //Verifica se existe referencia no item selecionado
   begin
     if TreeView1.Selected.Level = 1 then 
       //Verifica se estamos no segundo nível para poder deletar
     begin
        TCliente(TreeView1.Selected.Data).Telefones.Delete(TreeView1.Selected.Index);
        TreeView1.Selected.Delete;
     end;
   end;
 end;

   //TreeView : OnClick
  //Finalidade : Carregar para o Form as informações armazenadas no 
  //TreeView, permitindo exclusão ou alteração. 
 

procedure TFrmPrincipal.TreeView1Click(Sender: TObject);
begin
  ClearCliente;
  ClearTelefone;

  if TreeView1.Selected.Level = 0 then //Verifica se estamos no primeiro nível
  begin
    EdtCodigo.Text := IntToStr( TCliente(TreeView1.Selected.Data).Codigo );
    EdtNome.Text   := TCliente(TreeView1.Selected.Data).Nome;
    EdtCPF.Text    := TCliente(TreeView1.Selected.Data).CPF;
  end
  else
  if TreeView1.Selected.Level = 1 then //Verifica se estamos no segundo nível
  begin
    EdtCodigo.Text    := IntToStr( TCliente(TreeView1.Selected.Data).Codigo );
    EdtNome.Text      := TCliente(TreeView1.Selected.Data).Nome;
    EdtCPF.Text       := TCliente(TreeView1.Selected.Data).CPF;

    EdtDDD.Text       := TCliente(TreeView1.Selected.Data)
    .Telefones[TreeView1.Selected.Index].DDD;
    EdtNumero.Text    := TCliente(TreeView1.Selected.Data)
    .Telefones[TreeView1.Selected.Index].Numero;
    CbxTipo.ItemIndex := CbxTipo.Items
    .IndexOf(TCliente(TreeView1.Selected.Data)
    .Telefones[TreeView1.Selected.Index].Tipo);
  end;
end;

Testando o exemplo

Testando a aplicação

Fico por aqui e na próxima Quick Tips.