Fórum Rotina para preenchimento dos controles com as propriedades das classes #1835
12/01/2009
0
var
Count, Size, I: Integer;
List: PPropList;
PropInfo: PPropInfo;
Controle: TComponent;
begin
{ Contar quantas propriedade o objeto possui }
Count := GetPropList(Obj.ClassInfo, tkAny, nil); { Apontar para o Endereço de memória }
Size := Count * SizeOf(Pointer);
GetMem(List, Size); try
{ Contar quantas propriedades o objeto }
{ possui passando os dados para a Lista }
Count := GetPropList(Obj.ClassInfo, tkAny, List); { Varrer as propridades do objeto }
for I := 0 to Count - 1 do
begin
PropInfo := List^[I]; { procurar pelo controle correspondente a propriedade } { que neste caso terá o mesmo nome dela } with Screen.ActiveForm do
Controle := FindComponent( PropInfo^.Name ); if (Controle is TDateEdit) then
TDateEdit(Controle).Date := GetPropValue(Obj, PropInfo^.Name)
else if (Controle is TCalcEdit) then
TCalcEdit(Controle).Value := GetPropValue(Obj, PropInfo^.Name)
else if (Controle is TListBox) then
begin
{ aqui está a minha dúvida, quando a propriedade é um TCollection } { onde são armazenadas várias strings. Como preencher o listbox } { com essas strings }
end
else if (Controle is TTimeEdit) then
TTimeEdit(Controle).Hora := VarToDateTime(GetPropValue(Obj, PropInfo^.Name))
else if (Controle is TCustomEdit) then
TCustomEdit(Controle).Text := VarToStr(GetPropValue(Obj, PropInfo^.Name))
else if (Controle is TCheckBox) then
TCheckBox(Controle).Checked := GetPropValue(Obj, PropInfo^.Name); end; finally
{ Libero a memória }
FreeMem(List);
end; end;
Alexandre Neto
Curtir tópico
+ 0Posts
13/01/2009
Wesley Yamazack
Att,
Wesley Yamazack
Gostei + 0
14/01/2009
Wesley Yamazack
Muito interessante seu método, a abordagem que está utilizando é interessante pois aumenta o reuso através do RTTi, eu inseri alguns comentários com sugestões na execução de alguns métodos para otimizar o código.
Quanto ao Collection tenho a seguinte observação:
- Caso você sempre vá armazenar nesta collection uma série de Strings, recomendo o uso do TStringList ao invés do TCollection, fiz a implementação do método para preencher o ListBox a partir do StringList.
- Caso você vá armazenar na collection, objetos de diferentes classes, então preciso saber qual a versão do Delphi em que estás desenvolvendo, pois se for no Delphi 2007 poderemos usar uma abordagem baseada em uma Collection com Generics, porém se for em versões anteriores teremos que criar uma interface ou uma classe abstrata do qual descenderão todas as suas CollectionItems, pois precisaremos que as CollectionItems compartilhem de um comportamento comum para serem lidos e executados em seu método.
{---------------------------------------------------------------------}
{ preencher controles com os valores das propriedades }
{ da classe passada por parametro }
{---------------------------------------------------------------------}
class procedure TClasseViewBase.PreencherControles(Obj: TObject);
var
Count, Size, I, X: Integer;
List: PPropList;
PropInfo: PPropInfo;
Controle: TComponent;
listaValores:TStringList;
begin
{ Contar quantas propriedade o objeto possui }
Count := GetPropList(Obj.ClassInfo, tkAny, nil);
{ Apontar para o Endereço de memória }
Size := Count * SizeOf(Pointer);
GetMem(List, Size);
try
{ Contar quantas propriedades o objeto }
{ possui passando os dados para a Lista }
(* SUGESTÃO - Recomendo o uso do método GetPropList(Obj, List) pois já faz
a alocação de memória necessária para List, com isso, as três linhas acima poderiam
ser removidas *)
Count := GetPropList(Obj.ClassInfo, tkAny, List);
{ Varrer as propridades do objeto }
for I := 0 to Count - 1 do
begin
PropInfo := List^[I];
{ procurar pelo controle correspondente a propriedade }
{ que neste caso terá o mesmo nome dela }
with Screen.ActiveForm do
Controle := FindComponent( PropInfo^.Name );
if (Controle is TDateEdit) then
TDateEdit(Controle).Date := GetPropValue(Obj, PropInfo^.Name)
else if (Controle is TCalcEdit) then
TCalcEdit(Controle).Value := GetPropValue(Obj, PropInfo^.Name)
else if (Controle is TListBox) then
begin
{ aqui está a minha dúvida, quando a propriedade é um TCollection }
{ onde são armazenadas várias strings. Como preencher o listbox }
{ com essas strings }
{ GetObjectProp(Obj, PropInfo^.Name) -> Este método retorna a referência do objeto apontado pela property }
if GetObjectProp(Obj, PropInfo^.Name) is TStringList then
begin
{ Limpamos o listBox para não acumular os dados }
TListBox(Controle).Items.Clear;
{ Retorna para ListaValores a stringList que está na property }
listaValores := TStringList(GetObjectProp(Obj, PropInfo^.Name));
{ percorre a lista de valores da property e insere no ListBox }
for x:=0 to Pred(listaValores.Count) do
begin
TListBox(Controle).Items.Add(listaValores[x]);
end;
end
else if GetObjectProp(Obj, PropInfo^.Name) is TCollection then
begin
{ Caso precise armazenar em collections de diversos objetos, poderemos usar Collection com generics no caso do delphi 2007 ou teremos que criar uma classe abstrata herdando de TCollectionItem em versões anteriores }
end;
end
else if (Controle is TTimeEdit) then
TTimeEdit(Controle).Hora := VarToDateTime(GetPropValue(Obj, PropInfo^.Name))
else if (Controle is TCustomEdit) then
TCustomEdit(Controle).Text := VarToStr(GetPropValue(Obj, PropInfo^.Name))
else if (Controle is TCheckBox) then
TCheckBox(Controle).Checked := GetPropValue(Obj, PropInfo^.Name);
end;
finally
{ Libero a memória }
FreeMem(List);
end;
end;
Att,
Wesley Yamazack
Gostei + 0
14/01/2009
Alexandre Neto
private
FFONE : string;
function GetFONE: string;
procedure SetFONE(const Value: string);
public
constructor Create(Collection: TCollection); reintroduce; virtual;
destructor Destroy; override;
published
property ELEMENTO: string read GetFONE write SetFONE;
end; TFones = class(TCollection)
private
function GetFones(index: integer): TFone;
procedure SetFones(index: integer; const Value: TFone);
public
function Add: TFone;
property Items[index: integer]: TFone read GetFones write SetFones;
end; TContatoFones = class(TPersistent)
private
FID : integer;
FFones : TFones;
function GetID: integer;
procedure SetID(const Value: integer);
public
constructor Create;
destructor Destroy; override;
published
property ID : integer read GetID write SetID;
property FONES: TFones read FFones write FFones;
end;
[]s Alexandre Amaral.
Gostei + 0
14/01/2009
Alexandre Neto
Gostei + 0
14/01/2009
Wesley Yamazack
Como estamos trabalhando no Delphi 7, não poderemos usar Generics pois ainda não há nesta versão. Teremos que criar uma classe base para as classes associativas, como por exemplo TContatoFones, que faz a ligação entre Cliente e seus respectivos telefones.
Esta classe base, no qual chamei de "TCollectionObjects", terá dois métodos, um para retornar a descrição
que é o valor a ser exibido na tela e outro para retornar a collection manipulada pela classe. Isso é para verificarmos a quantidade de elementos na Collection e caso precise acessar os mesmos posteriormente
Estes métodos serão abstratos na classe base e serão implementados nas classes filhas, como por exemplo "TContatoFones" a implementação os mesmos está no aquivo, assim como alguns comentários para facilitar o entendimento.
{ Teremos que ter uma classe comum para ser chamada no método preencherControles }
{ Com isso as suas classes associativas herdariam desta classe base }
TCollectionObjects = class(TPersistent)
{ Este Método retornará a descrição desejada para o Objeto }
{ Com isso, ganha-se flexibilidade, pois hoje temos apenas a informação de telefone
porém pode-se ter também outros atributos como DDD por exemplo }
function getDescription(index:integer):String;virtual;abstract;
{ Este método retornará a collection manipulada pela classe concreta }
function getCollection:TCollection;virtual;abstract;
end;
{ A classe associativa passa a herdar de sua classe associativa Base
e a sobrescrever os métodos da mesma }
TContatoFones = class(TCollectionObjects)
{Abaixo estão os métodos sobrescritos na classe TContatoFones}
function getDescription(index:integer):String;override;
function getCollection:TCollection;override;
function TContatoFones.getDescription(index: integer): String;
begin
result := FFones.Items[index].ELEMENTO;
end;
function TContatoFones.getCollection: TCollection;
begin
result := FONES;
end;
{ No método preencherControles, declaramos outra variável do tipo de nossa classe base }
CollectionObj:TCollectionObjects;
{A implementação da rotina de preenchimento do controle com collection ficaria assim}
{Aqui verificamos se o atributo herda da classe associativa base TCollectionObjects}
if GetObjectProp(Obj, PropInfo^.Name).InheritsFrom(TCollectionObjects) then
begin
{ Limpamos o listBox para não acumular os dados }
TListBox(Controle).Items.Clear;
{ Retorna para ListaValores a stringList que está na property }
CollectionObj := TCollectionObjects(GetObjectProp(Obj, PropInfo^.Name));
{ percorre a collection}
for x:=0 to Pred(CollectionObj.getCollection.Count) do
begin
{Insere na listBox os valores dos objetos da collection}
TListBox(Controle).Items.Add(CollectionObj.getDescription(x));
end;
end;
======================================================================
Att,
Wesley Yamazack
Gostei + 0
14/01/2009
Alexandre Neto
Gostei + 0
14/01/2009
Wesley Yamazack
Abraço
Wesley Yamazack
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)