Converter String para TComponent??????

30/08/2004

0

Aê Galera..

Tudo bem?

É o seguinte, preciso converter uma classe armazenada no banco de dados, no formato string para TComponent..

Assim :

banco de dados

TRLLabel 0000000001
TRLMemo 0000000002
.
.
.

assim por diante, quero dar um select nos campos string e criar em RUN TIME os componentes, referêntes as classes armazenadas no banco..

tem como??

agradeço a todos antecipadamente..

Cabelo


Cabelo

Cabelo

Responder

Posts

25/07/2008

Fieldztime

Ola Amigão, tudo bem?, no delphi os componentes são da classe ´Tcomponent´, não podemos acessa-los por strings que é o seu caso, mas podemos chamar uma funcao chamanda FINDCOMPONENT que procura pelo nome que voce passar e retorna TCOMPONENT ou NIL <-caso nao achar por exemplo: digamos que vc tenha 3 Labels: Label1, label2 e label3

vamos mudar o caption do label2 pelo nome do componente, seria assim:


tlabel( findcomponent(´label2´) ).caption:=´Novo Caption do Label2!´;

para procurar em outros forms é a mesma coisa, se vc estiver no form1 para procurar no form2 é assim

tlabel( form2.findcomponent(´label2´) ).caption:=´Novo Caption do Label2!´;

dara uma excecao de erro se o componente nao existir, voce pode fazer assim para checar:

temp_comp: tcomponent;

temp_comp:= tlabel( form2.findcomponent(´label2´) );

if temp_comp<>nil then begin

tlabel( form2.findcomponent(´label2´) ).caption:=´Novo Caption do Label2!´;

end;

Simples, porém limitado.

Existe a Forma mais Complexa de fazer a mesma coisa:


i: integer;
begin


for i:=0 to form1.componentcount-1 do begin

if form1.components(i) is tlabel then begin

if tlabel( form1.components(i) ).caption=´label2´ then

tlabel( form1.components(i) ).caption:=´Novo Caption do Label2´;

end;

end;

end;

espero ter ajudado.


Responder

27/07/2008

Micheus

quero dar um select nos campos string e criar em RUN TIME os componentes, referêntes as classes armazenadas no banco.. tem como??

Veja se com este exemplo, vc consegue captar a idéia e implementar algo:
...
implementation
uses
  TypInfo;
{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
type
  TCompInfo = record
    ClassName :string;
    Top,
    Left,
    Width,
    Height :Integer;
    Text :string;
  end;

const
  CompInfoList :array[0..3] of TCompInfo =
                ((ClassName :´TLabel´; Top :8; Left :8; Width :30; Height :20; Text :´Nome:´),
                 (ClassName :´TEdit´;  Top :8; Left :58; Width :30; Height :20; Text :´´),
                 (ClassName :´TLabel´; Top :33; Left :8; Width :20; Height :20; Text :´Idade:´),
                 (ClassName :´TEdit´;  Top :33; Left :58; Width :10; Height :20; Text :´´));
var
  PClass: TPersistentClass;
  LForm :TCustomForm;
  LWinControl :TComponent;
  Idx,
  CompNum :Integer;
begin
  PClass := GetClass(´TForm´);
  if PClass <> nil then
  begin
   // criamos um Form em branco
    LForm := TComponentClass(PClass).Create(Application) as TCustomForm;
    LForm.Caption := ´Form dinâmico´;
    LForm.Top := 30;
    LForm.Left := 100;
    LForm.Width := 290;
    LForm.Height := 150;
    CompNum := 1;
   // colocaremos os componentes da lista neste form
    for Idx := 0 to 3 do
    begin
      PClass := GetClass(CompInfoList[Idx].ClassName);
      if PClass <> nil then
      begin
        LWinControl := TComponentClass(PClass).Create(LForm);
        TWinControl(LWinControl).Parent := LForm;
        TWinControl(LWinControl).Name := Format(´CompName¬d´, [CompNum]);
        TWinControl(LWinControl).Left :=  CompInfoList[Idx].Left;
        TWinControl(LWinControl).Top :=  CompInfoList[Idx].Top;
        TWinControl(LWinControl).Width :=  CompInfoList[Idx].Width;
        TWinControl(LWinControl).Height :=  CompInfoList[Idx].Height;
        TWinControl(LWinControl).SetTextBuf(PChar(CompInfoList[Idx].Text));
        Inc(CompNum);
      end;
    end;
    LForm.ShowModal;
    LForm.Release;
  end;
end;

initialization
  RegisterClass(TForm);
  RegisterClass(TLabel);
  RegisterClass(TEdit);

end.

Para que funcione o uso de [i:92e92915d0]GetClass[/i:92e92915d0], é necessário que vc registre as classes desejadas em um statement [i:92e92915d0]initialization[/i:92e92915d0], como fiz no exemplo.

Veja o que consegue, e qualquer dúvida pergunte. Talvez consiga lhe ajudar mais.

Abraços


Responder

28/07/2008

Cabelo

Acho que não conseguí explicar direito minha dúvida.

É o seguinte, vou precisar de criar em tempo de execução os componentes que o usuário selecionar, na verdade o usuário é que irá montar o relatório com os campos que ele desejar usar, mas para isso preciso de saber quais componentes irei disponibilizar.

Por isso preciso de ler o nome da string que o usuário selecionar e criar o componente.


Responder

28/07/2008

Marco Salles

´mais ou menos para voce ter uma idéia :

var
  newObj:TControl;

procedure TForm1.Button1Click(Sender: TObject);
var
umaClasse:TClass;
begin
umaClasse:=GetClass(edit1.Text);
if umaclasse <> nil then
NewControl(umaClasse);
end;

procedure TForm1.NewControl(ClassRef: TClass);
begin
  newObj:=TControlClass(ClassRef).Create(self);
  newObj.Parent:=self;
//colocar Nome
//Atribuir tamanho...
//Atribuir eventos
//posicionr etc...
end;

initialization
registerClass(Tedit);


apesar de não ter lido eu acho que a dica do micheus te atende tb


Responder

29/07/2008

Cabelo

Marcos..

Eu usei exatamente como você passou e funciona perfeitamente desde o ano passado...

var 
  v_componente : TControl; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
v_classe :TClass; 
begin 
v_classe := GetClass(cdsComponente.FieldByName(´C_COMPONENTE´).AsString); 
if v_classe <> nil then 
P_Cria_Componente(v_classe); 
end; 

procedure P_Cria_Componente(l_class : TClass); 
begin 
  v_componente := TControlClass(l_class).Create(Self); 
  v_componente.Parent := Self; 
  P_Configura_Control(v_componente)
end; 

initialization 
registerClass(Tedit);



mas tive que implementar usando RTTI pois o usuário ´configura´ a tela em run - time... na procedure P_Configura_Control(l_componente : TComponent)

A dica do nosso amigo micheus atende, mas deixa fixo as configurações do TCcontrol. Mas uma coisa me ajudou, tive a idéia de criar um vetor dinâmico com oc componentes, ao invés de ficar criando variáveis, deixo tudo num memso lugar e só uso um ponteiro.

Mesmo assim, este tópico foi ´renascido´ esses dias... rssss..

Coloquei este tópico em 2004, hoje já resolví o problema usando como descreví acima..

mesmo assim muito obrigado..


Responder

31/07/2008

Micheus

A dica do nosso amigo micheus atende, mas deixa fixo as configurações do TCcontrol.

[b:aac9d78e97]Cabelo[/b:aac9d78e97], a questão do type-cast para TWinControl está relacionada ao fato de que todos os componentes [b:aac9d78e97]visuais[/b:aac9d78e97] deverão ser descendentes deste.

Como o modo de construir dinamicamente componentes a partir do nome da classe passa pelo uso desta ´formula´:
[color=blue:aac9d78e97][i:aac9d78e97]<variável TComponent> := TComponentClass(<nome da classe>).Create(<owner>);[/i:aac9d78e97][/color:aac9d78e97]

temos que levar em conta que os componentes visuais tem as propriedades de posicionamento e muitas outras que não estão disponíveis na classe TComponent.

Observe ainda, que para generalizar qualquer atribuição que deveria ser feita à Caption (no caso de um TLabel) ou a Text (no caso de um TEdit), fiz uso do método [i:aac9d78e97]SetText[/i:aac9d78e97] que se aplicará a qualquer dos casos, sem que tenhamos que saber quem é quem.

O uso de um vetor constante, foi apenas uma forma de simplificar uma situação em que a lista seria obtida dos registros de de uma tabela.

Abraços


Responder

01/08/2008

Cabelo

É isso mesmo micheus...

Implementei minha solução com a idéia de um vetor do tipo record e ficou perfeito.. está funcionando mais rápido e a codificação ficou muito mais simples..

Obrigado pela sua idéia..

Abs


Responder

01/08/2008

Marco Salles

citação de marcosalles
apesar de não ter lido eu acho que a dica do micheus te atende tb


na verdade passei o olho e vi que tb atendia

Agora quanto a ser mais rápido é claro que sera pq na implementação que o Cabel uzou continha codigo de RTTI ... Ora RTTI so em ultimo caso.

citação de cabelo:
mas tive que implementar [b:8534ca7380]usando RTTI [/b:8534ca7380]pois o usuário ´configura´ a tela em run - time



Responder

04/08/2008

Cabelo

marcos.. desculpe a ignorancia, mas pq somente em último caso o uso de RTTI, para fazer o q faço, utilizar um Object Inspector em RUN Time, que será configurado pelo usuário, com qual tecnologia eu deveria criar o object inspector, só lembrando que os componentes são criados em run-time ?


Responder

05/08/2008

Discorpio

Bom dia a todos.

Se não me falhe a memória, a partir do Delphi 6, o mesmo disponibilizou duas funções que converte a configuração do componente em string e vice-versa, são elas:


  // Converte componente para string
  ObjectBinaryToText(BinStream, StrStream);

  // Converte string para componente.
 ObjectTextToBinary(StrStream, BinStream);



Entretanto estas funções devem ser usadas em conjunto com um TMemoryStream, assim sugiro que voce crie as seguintes Funções.


// Para transformar componente em string.
function TForm1.ComponentToString(Component: TComponent): string;
var
  BinStream:TMemoryStream;
  StrStream: TStringStream;
  s: string;
begin
  BinStream := TMemoryStream.Create;
  try
    StrStream := TStringStream.Create(s);
    try
      BinStream.WriteComponent(Component);
      BinStream.Seek(0, soFromBeginning);
      ObjectBinaryToText(BinStream, StrStream);
      StrStream.Seek(0, soFromBeginning);
      Result:= StrStream.DataString;
    finally
      StrStream.Free;
    end;
  finally
    BinStream.Free
  end;
end;


// Para transformar string em componente.
function TForm1.StringToComponent(Value: string): TComponent;
var
  StrStream:TStringStream;
  BinStream: TMemoryStream;
begin
  StrStream := TStringStream.Create(Value);
  try
    BinStream := TMemoryStream.Create;
    try
      ObjectTextToBinary(StrStream, BinStream);
      BinStream.Seek(0, soFromBeginning);
      Result := BinStream.ReadComponent(nil);
    finally
      BinStream.Free;
    end;
  finally
    StrStream.Free;
  end;
end;



So não esqueça de registrar a classe do componente que voce está convertendo para String ao final da Unit do seu formulário, assim:


procedure TForm1.btnQualquerClick(Sender: TObject);
begin
  .....
  ....
end;

initialization
RegisterClass(TLabel);

end.



Um abraço.


Responder

05/08/2008

Cabelo

Então..

Sua Dica funciona, mas isso se o usuário não tiver que selecionar o componente que ele quer usar, eu disponibilizo os componentes para ele montar a tela como preferir e portanto não posso registrar na unit os componentes, já que não sei quais componentes serão usados.. sem contar que o usuário também vai ´configurar´ o componente selecionado através de um object inspector, como no desenvolvimento em project - time

Correto ??

Ou será que sou eu que não tô entendendo o que vc quis dizer ?

Abs


Responder

30/09/2008

Micheus

[b:796b9f37c0]Cabelo[/b:796b9f37c0], a proposta do colega [b:796b9f37c0]Discorpio[/b:796b9f37c0] seria aplicável em uma situação em que o usuário já desenhou o seu form e vai salvá-lo para depois recuperá-lo. Estas funções permitem fazer exatamente o que o Delphi faz quando grava as definições do form nos arquivos [i:796b9f37c0].dfm[/i:796b9f37c0] e quando restaura ele, a partir do arquivo, para edição. Assim, para gravar, o objeto já deve existir na memória e para carregar ele já deve existir gravado em algum lugar (stream - disco, blob,...).

Talvez vc possa associar as duas coisas para ter um editor mais completo, gravando em um blob o form desenhado e depois recuperando ele de lá, para uso ou edição.

Abraços


Responder

Que tal ter acesso a um e-book gratuito que vai te ajudar muito nesse momento decisivo?

Ver ebook

Recomendado pra quem ainda não iniciou o estudos.

Eu quero
Ver ebook

Recomendado para quem está passando por dificuldades nessa etapa inicial

Eu quero

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar