[Delphi] Usando RTTI para exibir dados de um objeto em componentes visuais

Saudações, amigos!
Vejam só o RTTI entrando novamente na pauta de artigos! Tive uma boa recepção com o artigo sobre validações com RTTI e decidi abordar um pouco mais sobre este recurso.
Dessa vez, utilizaremos o RTTI para preencher os campos de um formulário de acordo com os valores das propriedades de um objeto de negócio. Confira o artigo!

Introdução

Quando trabalhamos com algum padrão de arquitetura, como MVC (Model-View-Controller) ou MVP (Model-View-Presenter), existe uma camada de modelagem (Model) que comporta as classes de negócio, geralmente mapeadas conforme as tabelas do banco de dados. A criação dessas classes é resultado de uma técnica de desenvolvimento conhecida como ORM (Object-relational Mapping), que visa simplificar as operações de persistência através do mapeamento das tabelas.

Há várias formas de apresentar os dados recuperados de uma consulta no banco de dados na camada de visão (View). Uma delas é trazer uma lista de objetos, considerando que cada objeto representa um registro retornado na consulta. Para facilitar esse entendimento, considere, por exemplo, que existam três funcionários cadastrados da cidade de Maringá. Para trazê-los, executaríamos a consulta abaixo:

O resultado dessa consulta é uma lista de objetos com três instâncias da classe de funcionários (como TFuncionario). Pois bem, ao receber essa lista de objetos na camada View, devemos exibir os valores do funcionário selecionado nos controles de tela, porém, a lista não possui uma propriedade para conexão com um DataSource. E agora?

Dá-lhe RTTI!

Para apresentar estes dados, faremos o RTTI entrar em cena!

Considere a existência de uma classe de funcionários com os seguintes atributos:

Dado que o exemplo é didático, não me preocupei com o encapsulamento de Getters e Setters, ok?

Considere também que a nossa View (neste caso, um formulário) recebe uma lista de objetos do tipo TFuncionario:

A nossa missão, com RTTI, é codificar a exibição dos dados na tela de exemplo abaixo, sem trabalhar com a propriedade Data do TClientDataSet e também dispensando o recurso de LiveBindings.

Tela de exemplo para preenchimento dos componentes com RTTI

Vamos lá!

Observe que há somente a coluna “Nome” no componente TDBGrid. A ideia é que, ao clicar no nome do funcionário, os dados sejam exibidos no painel à direita. Primeiro, portanto, codificaremos uma rotina para preencher o nosso DataSet, no qual possui apenas um Field chamado “Nome”, adicionado manualmente pelo Fields Editor.

Fácil, não? Mesmo assim, vale a explicação:

  • Criamos um objeto do tipo TRttiContext para acessar os dados de estruturas de classes;
  • Usamos um objeto do tipo TRttiType para ler a estrutura da classe TFuncionario;
  • Invocamos o método GetProperty para obter a propriedade “Nome” como TRttiProperty;
  • Dentro do for-in, extraímos o valor da propriedade “Nome” de cada objeto através do método GetValue.

Ao executar o método acima, a nossa Grid já apresenta os dados:

DBGrid preenchida com dados capturados via RTTI

O próximo passo é exibir os dados do funcionário selecionado na Grid, percorrendo as propriedades do objeto atual da lista. No entanto, mais uma vez, não existe uma forma visual de associar as propriedades do objeto com os controles da tela, portanto, devemos criar algum tipo de associação por conta própria. Pensei, então, em renomear cada componente visual da tela com o nome da respectiva propriedade, precedido do prefixo “Campo”. Este foi o resultado:

Nomes dos componentes para associar com propriedades do objeto

Feito isso, codificaremos um método que percorrerá as propriedades do objeto e, para cada uma, encontrará o componente na tela (com base no prefixo “Campo”) para preencher o valor.

Porém, observe que há vários tipos de componentes na tela: TEdit, TComboBox, TRadioGroup, TDateTimePicker, TTrackbar, TShape e TCheckBox. Como a atribuição de valor para cada um deles é feita de forma diferente (propriedades Text, ItemIndex, Position, Date e Checked), é necessário testar se o componente encontrado é de uma classe específica e, em caso positivo, converter o componente para prosseguir com a atribuição. Para isso, utilizaremos os operadores is e as do Delphi para trabalhar com conversão segura, principalmente para evitar as exceções de Invalid Typecast.

Chega de conversa e vamos à codificação!

Bom, acredito que os comentários no código são autoexplicativos, não é? 🙂

Você deve notado que este método recebe um objeto do tipo TFuncionario como parâmetro. Este objeto está contido na lista de objetos (FListaFuncionarios) e devemos acessá-lo pelo índice do registro selecionado na Grid. Faremos isso através do evento AfterScroll do nosso DataSet, chamando o método acima:

Por que o “Pred”?
A propriedade RecNo inicia no número 1, enquanto os índices de lista iniciam no 0, então é preciso decrementar o valor.

Pessoal, aproveitando o ensejo, é importante destacar que utilizo o RecNo aqui apenas para fins didáticos. Em um ambiente real, em que é possível adicionar, editar e remover registros, eu sugiro que o mecanismo de acesso ao índice da lista seja mais confiável.

Por fim, vejam só o resultado final:

Controles visuais preenchidos através de RTTI

 

Caso queiram baixar este projeto de exemplo, acesse o link abaixo do meu GitHub:

https://github.com/AndreLuisCelestino/Exemplos-Blog/tree/master/PreenchimentoComRTTI

Fico por aqui com mais essa colaboração sobre RTTI.
Um grande abraço!


André Celestino