Converter String para TComponent??????
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
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
Curtidas 0
Respostas
Fieldztime
30/08/2004
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.
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.
GOSTEI 0
Micheus
30/08/2004
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
GOSTEI 0
Cabelo
30/08/2004
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.
É 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.
GOSTEI 0
Marco Salles
30/08/2004
´mais ou menos para voce ter uma idéia :
apesar de não ter lido eu acho que a dica do micheus te atende tb
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
GOSTEI 0
Cabelo
30/08/2004
Marcos..
Eu usei exatamente como você passou e funciona perfeitamente desde o ano passado...
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..
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..
GOSTEI 0
Micheus
30/08/2004
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
GOSTEI 0
Cabelo
30/08/2004
É 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
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
GOSTEI 0
Marco Salles
30/08/2004
citação de marcosalles
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:
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
GOSTEI 0
Cabelo
30/08/2004
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 ?
GOSTEI 0
Discorpio
30/08/2004
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:
Entretanto estas funções devem ser usadas em conjunto com um TMemoryStream, assim sugiro que voce crie as seguintes Funções.
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:
Um abraço.
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.
GOSTEI 0
Cabelo
30/08/2004
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
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
GOSTEI 0
Micheus
30/08/2004
[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
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
GOSTEI 0