Converter String para TComponent??????
30/08/2004
0
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
Posts
25/07/2008
Fieldztime
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.
27/07/2008
Micheus
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
28/07/2008
Cabelo
É 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.
28/07/2008
Marco Salles
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
29/07/2008
Cabelo
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..
31/07/2008
Micheus
[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
01/08/2008
Cabelo
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
01/08/2008
Marco Salles
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:
04/08/2008
Cabelo
05/08/2008
Discorpio
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.
05/08/2008
Cabelo
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
30/09/2008
Micheus
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
Clique aqui para fazer login e interagir na Comunidade :)