Fala galera, beleza?
Hoje eu trago para vocês uma forma simples e objetiva de adicionar e manipular propriedades adicionais aos nós de um TreeView.
A classe TTreeView é um dos componentes visuais da aba Win32. Esse componente representa uma estrutura organizada em níveis de profundidade, criado uma relação de “nós pai e nós filhos”.
Visualmente ela lembra uma árvore e provavelmente foi daí que o nome saiu, hehe.
TTreeNode
TTreeNode é a classe que dá suporte à coleção de itens de um TTreeView. Podem ser acessados através da propriedade Items: MyTreeView.Items.
Estendendo a classe TTreeNode nós podemos aproveitar o seu comportamento e então adicionar as nossas particularidades.
A classe TCustomNode
1 2 3 4 5 6 7 8 |
type TCustomNode = class(TTreeNode) public property Title: string; property Color: TColor; property CustomMessage: string; property IsAdmin: Boolean; end; |
Eu utilizei o recurso de herança da POO para criar uma classe chamada TCustomNode. Nessa classe, adicionei algumas propriedades que julguei serem necessárias para resolver o meu problema. O nome da classe não é uma regra. A mesma classe poderia ter o nome de TBanana ou TItemFinanceiro. Com isso, temos toda a liberdade de adicionar ou remover propriedades e ainda assim, aproveitar as vantagens de um TTreeNode.
Populando a árvore de nós e manipulando as propriedades customizadas.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
procedure TFrmPrincipal.Supply; var MainNode: TTreeNode; ChildNode: TCustomNode; begin //Criação do nó principal da minha TreeView MainNode := trvFoo.Items.Add(Nil, 'Nó principal'); //Criação do Node customizado. Aproveitamos o .Create do TTreeNode //onde a "coleção de nós alvo" é um parâmetro obrigatório. ChildNode := TCustomNode.Create(trvFoo.Items); ChildNode.Title := 'Item tela 1'; ChildNode.Color := clRed; ChildNode.CustomMessage := 'Mensagem customizada 1'; ChildNode.IsAdmin := False; trvFoo.Items.AddNode(ChildNode, MainNode, ChildNode.Title, nil, naAddChild); ChildNode := TCustomNode.Create(trvFoo.Items); ChildNode.Title := 'Item tela 2'; ChildNode.Color := clBlue; ChildNode.CustomMessage := 'Mensagem customizada 2'; ChildNode.IsAdmin := False; trvFoo.Items.AddNode(ChildNode, MainNode, ChildNode.Title, nil, naAddChild); ChildNode := TCustomNode.Create(trvFoo.Items); ChildNode.Title := 'Item tela 3'; ChildNode.Color := clGreen; ChildNode.CustomMessage := 'Mensagem customizada 3'; ChildNode.IsAdmin := True; trvFoo.Items.AddNode(ChildNode, MainNode, ChildNode.Title, nil, naAddChild); end; |
Implementei um simples método chamado Supply para criar e alimentar os nós da nossa TreeView. Utilizei uma variável do tipo TCustomNode para poder manipular as suas propriedades.
1 |
trvFoo.Items.AddNode(ChildNode, MainNode, ChildNode.Title, nil, naAddChild); |
O método AddNode é responsável por adicionar e “aninhar” os nós dentro da estrutura de árvore. O primeiro parâmetro é o nó a ser adicionado. O segundo, é o relativenode, ou seja, o nó “pai” do novo nó adicionado. O terceiro é a string de exibição do novo nó (texto a ser apresentado na estrutura). O quarto parâmetro representa um ponteiro que pode ser atrelado ao nó que está sendo adicionado. Essa pratica do ponteiro é bastante eficaz, mas exige um tratamento e uso de técnicas um pouco mais complexas. E por último, porém não menos importante, temos o NodeAttachMode. O quinto parâmetro determina a forma em que o novo nó será tratado no momento da “adição” à lista de nós.
Graças ao polimorfismo, foi possível utilizar um objeto do tipo TCustomNode no método AddNode.
Feito isso, temos uma rotina que cria um nó principal (nó pai) e que também cria nós filhos do tipo TCustomNode, manipula suas propriedades únicas e os adiciona na estrutura de árvore como filhos do nó principal.

Aplicabilidade
Podemos aplicar este recursos em dezenas de casos diferentes. Eu mesmo já tive a oportunidade de operar sistemas que não utilizavam menus convencionais (TMainMenu), mas sim uma estrutura em árvore (criada com uma treeview) que representava os menus disponíveis para navegação.
Na prática
Implementei o evento OnChange da nossa TTreeView de exemplo, confira:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
procedure TFrmPrincipal.trvFooChange(Sender: TObject; Node: TTreeNode); var NodeSelecionado: TCustomNode; begin NodeSelecionado := TCustomNode(Node); //Simples verificação para me assegurar de que o nó realmente existe if NodeSelecionado <> nil then begin //Verificando se de fato o nó é do tipo esperado if NodeSelecionado.ClassNameIs('TCustomNode') then begin lblTitle.Caption := NodeSelecionado.Title; lblTitle.Font.Color := NodeSelecionado.Color; lblCustomMessage.Caption := NodeSelecionado.CustomMessage; btnAdmin.Enabled := NodeSelecionado.IsAdmin; end else begin lblTitle.Caption := 'Não é um nó customizado'; lblCustomMessage.Caption := ''; end; end; end; |
Eu utilizei um simples typecast para capturar o nó “alvo” do evento e transforma-lo em TCustomNode. Verifiquei se ele realmente é do tipo esperado e manipulei os elementos do meu formulário conforme as propriedades do nó selecionado.
É possível aproveitar este recurso e criar telas dinamicamente, alterar títulos, aplicar filtros e outras coisas.
Muito bom.