Atenção: por essa edição ser muito antiga não há arquivo PDF para download. Os artigos dessa edição estão disponíveis somente através do formato HTML.
Dica
Os objetos TtreeView e TTreeNode
Uma das formas de exibição de dados utilizadas amplamente hoje em dia é a estrutura denominada Árvore, popularizada entre nós pelo Windows Explorer. Para a criação de uma árvore em aplicação que utiliza a estrutura de árvore, o Delphi disponibiliza a classe TTreeView.
Esta classe é de fácil utilização. Para carregar dados em um TreeView a partir de um banco de dados e recuperá-los, utilizamos os métodos AddObject e AddChildObject. Para isto é necessário utilizar um parâmetro do tipo untyped pointer que irá preencher a propriedade Data do objeto TTreeNode.
Irei mostrar neste artigo como construir uma aplicação que mostra os clientes e seus respectivos pedidos na arvore e ao clicar nas ramificações do pedido, um grid mostra os seus respectivos itens. No Delphi, crie uma nova aplicação e no form coloque um objeto TtreeView que se encontra na paleta Win32 e um objeto DBgrid que se encontra na paleta DataControls. O Banco de dados que iremos acessar terá três tabelas:Clientes, Pedidos e Itens e Produtos. Coloque quatro componentes Ttable que se encontram na paleta BDE e quatro objetos dataSource que se encontra na paleta DataAccess. Ligue os quatro objetos table com as tabelas e cada datasource. Veja o formulário em tempo de projeto na figura 1.
Figura 1: o exemplo em execução
Para criar a árvore, criaremos uma procedure que preencherá o nível zero da mesma. Não tente criar a árvore e todos os seus níveis de uma só vez, pois este processo se tornará demorado demais. O ideal é que os demais níveis sejam criados somente quando usuário clicar em um dos nós da árvore. Na seção Private do Form declare a seguinte procedure:
procedure Tform1.
PreencheArvore (Tabela:
TTable);
var
Pont: Tpont;
begin
while not Tabela.Eof do
begin
New (Pont):
Pont^ : = Tabela.
Fieldbyname (‘Codigo’)
.asInteger;
TV.Items.AddObject (nil,
Tabela.Fieldbyname
(‘nome’).asString, pont);
Tabela.Next;
end;
end;
Neste momento seu programa deverá realizar uma consulta ao banco de dados para facilitar quais registros ficarão neste ramo de sua árvore. Em nosso exemplos, duas tabelas criarão a árvore: CLIENTE e PEDIDOS. E duas outras serão utlizadas para o peencimento do Grid: PRODUTO e ITENS.
Repare que o relacionamento entre as tabelas foi implementado através das propriedades MasterSource e MasterField, sendo utilizada também a propriedade Filter para selecionar os pedidos de um determinado cliente.
O campo descrição pode ser atribuído para a propriedade tect do objeto TtreeNode, e a chave primária deste registro deve ficar guardada em uma variável dinâmica acessada através do ponteiro encontrado na propriedade Data do objeto.
O motivo de criarmos uma variável do tipo Pointer é muito simples: A necessidade de armazenar chaves primárias compostas.
Em nosso exemplo as tabelas utilizadas no TTreeView possuem uma chave primária simples, e por isso criaremos um ponteiro para números inteiros. Caso suas tabelas possuam chaves primárias compostas e com estruturas diferentes, você deverá criar um tipo record para cada chave e um ponteiro para cada tipo record.
A manipulação da propriedade Data é a mesma utilizada para qualquer ponteiro: você deve primeiramente criar uma variável dinâmica com o método New, preenchê-la, e atribuir o endereço desta variável à propriedade Data.
Figura2. o exemplo em templo de projeto
New (Pont):
Pont^ : = Tabela.
Fieldbyname (‘Codigo’)
.asInteger;
TV.Items.AddObject (nil,
Tabela.Fieldbyname
(‘nome’).asString,pont);
Para recuperar os dados apontados pela propriedade Data do TtreeNode você deve utilizar um recurso de programação conhecido como Type cast, ou seja você informa o tipo com o qual você quer ler aquele objeto. Porém, você deve observar que este recurso só será bem sucedido quando utilizado com tipos compatíveis. A sintaxe de um Typecast é a seguinte: Tipo (Objeto ou variável).
Crie sua precedure para leitura dos dados armazenados na propriedade data, siga o exemplo aqui exibido e apresente em sua aplicação uma interface com a qual o usuário já está muito familiarizado. Segue abaixo o código completo da aplicação:
unit UTree;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Buttons, StdCtrls, DB, DBTables, Grids, DBGrids, ComCtrls, ExtCtrls;
type
TForm1 = class(TForm)
TV: TTreeView;
DBGrid1: TDBGrid;
TBClientes: TTable;
TBPedidos: TTable;
TBIten: TTable;
TBProduto: TTable;
DSClientes: TDataSource;
DSPedidos: TDataSource;
DSProduto: TDataSource;
DSIten: TDataSource;
Database1: TDatabase;
TBClientesCODIGO: TIntegerField;
TBClientesNOME: TStringField;
TBClientesENDERECO: TStringField;
TBPedidosCODIGO: TIntegerField;
TBPedidosDATA: TDateTimeField;
TBPedidosCODCLIENTE: TIntegerField;
procedure TVClick(Sender: TObject);
procedure DSClientesDataChange(Sender: TObject; Field: TField);
procedure FormShow(Sender: TObject);
procedure DSPedidosDataChange(Sender: TObject; Field: TField);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
procedure preenchearvore(Tabela:Ttable);
Procedure preenchegalho(Tabela:TTable);
{ Public declarations }
end;
TPont=^Integer;
var
Form1: TForm1;
implementation
{$R *.dfm}
Procedure Tform1.preenchearvore(Tabela:TTable);
var
Pont: TPont;
begin
while not Tabela.Eof do
begin
New (Pont);
Pont^ := Tabela.Fieldbyname ('Codigo').asInteger;
TV.Items.AddObject (nil,Tabela.Fieldbyname('nome').asString, pont);
Tabela.Next;
end;
end;
Procedure Tform1.preenchegalho(Tabela:TTable);
var
Pont:TPont;
begin
If Tv.Selected.haschildren then
exit;
while not tabela.eof do
begin
New(pont);
Pont^:=Tabela.Fieldbyname ('codigo').asInteger;
TV.Items.AddChildObject (TV.Selected,'Pedido: '+Tabela.Fieldbyname('codigo').asString+
' - '+Tabela.Fieldbyname ('data').asString,pont);
Tabela.Next;
end;
end;
procedure TForm1.TVClick(Sender: TObject);
begin
If TV.Selected.Level < 1 then
If TBClientes.FindKey([Tpont(TV.Selected.Data)^]) then
preenchegalho(TBPedidos)
else
else
TBPedidos.FindKey([Tpont(TV.Selected.Data)^]);
end;
procedure TForm1.DSClientesDataChange(Sender: TObject; Field: TField);
begin
TBPedidos.Filter:='codcliente = '+ tbclientes.fieldbyname('codigo').AsString;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
Tbclientes.open;
TBPedidos.Open;
TBIten.open;
TBProduto.open;
preenchearvore(TBClientes);
end;
procedure TForm1.DSPedidosDataChange(Sender: TObject; Field: TField);
begin
tbiten.Filter:='codpedido = '+ tbpedidos.Fieldbyname('codigo').asstring;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Tbclientes.close;
TBPedidos.close;
TBIten.close;
TBProduto.close;
end;
end.