Criação/Destruição de forms apenas pelo nome
Uma coisa que eu sempre me perguntei e venho procurando há uns dois anos, mas sem sucesso, era como criar forms sem a unit delas estar no seu uses, sem ter acesso a implementação da classe dessa form, mas simplesmente puder gravar o nome de uma form no banco de daddos e recuperar depois, podendo abrir a form apenas pelo nome dela.
hoje eu aprendi uma maneira de se fazer isso:
basta colocar nas units das forms:
sendo Tform3 o nome da classe da sua form.
depois, na form que vai ser chamada, mais especificamente na procedure que vai chamar as outras forms, é só fazer:
eu fiz isso no evento onclick de um botão, mas pode ser uma procedure que aceite como parametro uma string do nome da classe da form. Se for o nome da form, basta concatenar um T antes.
agora eu gostaria de saber se isso é uma boa prática ou se eh uma prática ruim, e se ela leva a algum bug ou perda de performance, memory leak etc.
valew!
hoje eu aprendi uma maneira de se fazer isso:
basta colocar nas units das forms:
initialization RegisterClass(TForm3); finalization UnRegisterClass(TForm3);
sendo Tform3 o nome da classe da sua form.
depois, na form que vai ser chamada, mais especificamente na procedure que vai chamar as outras forms, é só fazer:
procedure TChamadora.btn1Click(Sender: TObject); var ClasseDoObjejetoChamado: TFormClass; ObjetoDaClasseChamada: TForm; begin ClasseDoObjejetoChamado := TFormClass(GetClass(edt1.Text)); ObjetoDaClasseChamada := ClasseDoObjejetoChamado.create(nil); with ObjetoDaClasseChamada do begin Show; { showmodal; release; } end; end;
eu fiz isso no evento onclick de um botão, mas pode ser uma procedure que aceite como parametro uma string do nome da classe da form. Se for o nome da form, basta concatenar um T antes.
agora eu gostaria de saber se isso é uma boa prática ou se eh uma prática ruim, e se ela leva a algum bug ou perda de performance, memory leak etc.
valew!
Vitor Rubio
Curtidas 0
Respostas
Marco Salles
13/03/2006
Uma coisa que eu sempre me perguntei e venho procurando há uns dois anos......
...podendo abrir a form apenas pelo nome dela.
hoje eu aprendi uma maneira de se fazer isso:
eu fiz isso no evento onclick de um botão, mas pode ser uma procedure que aceite como parametro uma string do nome da classe da form. Se for o nome da form, basta concatenar um T antes.
sinceramente , acho que voce ainda não aprendeu..
Se voce mesmo diz que tem que concatenar um ´T´ antes , de fato voce não esta criando o formulario apenas com o nome
Mas se voce quiser mesmo saber qual a tecnica que se constroi formulario somente pelo nome sem ter que concatenar nada , deve procurar sobre Factory Method
agora eu gostaria de saber se isso é uma boa prática ou se eh uma prática ruim, e se ela leva a algum bug ou perda de performance, memory leak etc.
Usando o [b:c97fde76fb]Factory Method [/b:c97fde76fb], o que posso falar é que é uma execelente tecnica , resulta em codigos mais limpos , mais facilidade na manutenção , o formulario principal ,passa a não saber como os formularios estão sendo criados.. Enfim uma sperie de vantagens
GOSTEI 0
Marco Salles
13/03/2006
Ha desculpe a conexão caiu antes que eu conclui-sse
No método Factory Method para criar um Form voce simplesmente vai fazer assim
e os parametros da procedure criarForm saõ assim
se voce quiser se aprofundar mais e não achar nada sobre o método eu posso lhe passar mais detalhes
boa sorte
No método Factory Method para criar um Form voce simplesmente vai fazer assim
procedure TForm1.Button1Click(Sender: TObject); begin CriarForm(´form2´); end;
e os parametros da procedure criarForm saõ assim
procedure CriarForm(nomeform:String);
se voce quiser se aprofundar mais e não achar nada sobre o método eu posso lhe passar mais detalhes
boa sorte
GOSTEI 0
Vitor Rubio
13/03/2006
Então, eu fiquei empolgado porque aprendi isso aí hoje, e criar uma form através do nome..... mesmo que seja o nome da classe, já quebra meu galho. Mas eu percebi que era uma gambiarra tremenda, por isso eu perguntei se era uma boa prática.
Gostaria de aprender mais sobre [b:30519434b0]Factory Method [/b:30519434b0], visto que nunca ouvi falar, nem sei o que é.
Gostaria de aprender mais sobre [b:30519434b0]Factory Method [/b:30519434b0], visto que nunca ouvi falar, nem sei o que é.
GOSTEI 0
Michael
13/03/2006
[b:f0a32fbba6]Factory Method[/b:f0a32fbba6] é um design pattern [b:f0a32fbba6]criacional[/b:f0a32fbba6] catalogado pela famosa [b:f0a32fbba6]GoF[/b:f0a32fbba6] (Gang of Four). A função deste modelo é ´criar uma instância de várias classes derivadas´.
Você pode encontrar mais informações - e exemplos em C#, Delphi, Java e C++ - em http://www.oodesign.com.br/patterns/FactoryMethod.html. E também neste excelente site (em inglês) http://www.dofactory.com/Patterns/PatternFactory.aspx.
Também saiu um artigo sobre design patterns na edição 69 da revista ClubeDelphi, que abordou exatamente o modelo Factory Method. O exemplo usado pelo autor parece ser o mesmo citado pelo colega [b:f0a32fbba6]Marcos Salles[/b:f0a32fbba6], onde cada formulário se registra na ´fábrica´ de objetos. Só não gosto de uma coisa nesta abordagem: usar strings para identificar os forms, pois caso o nome seja digitado incorretamente o compilador não irá gerar nenhum aviso, por razões óbvias. Prefiro passar a definição classe que quero que a fábrica crie para mim.
Por fim, se quiser se aprofundar em design patters - algo extremamente aconselhável - visite os mesmos sites que indiquei acima, mas através destas URL´s:
http://www.oodesign.com.br/patterns/
http://www.dofactory.com/Patterns/Patterns.aspx
A diferença é que estes links levarão vc para a lista de todos os design patterns da GoF. Aliás, os exemplos do site [b:f0a32fbba6]oodesign [/b:f0a32fbba6]são os mesmos do [b:f0a32fbba6]Data & Object Factory[/b:f0a32fbba6], mas traduzidos para o português. Infelizmente nem todos os patterns constam na lista do site brasileiro ainda. Mas devem aparecer em breve.
[]´s
Você pode encontrar mais informações - e exemplos em C#, Delphi, Java e C++ - em http://www.oodesign.com.br/patterns/FactoryMethod.html. E também neste excelente site (em inglês) http://www.dofactory.com/Patterns/PatternFactory.aspx.
Também saiu um artigo sobre design patterns na edição 69 da revista ClubeDelphi, que abordou exatamente o modelo Factory Method. O exemplo usado pelo autor parece ser o mesmo citado pelo colega [b:f0a32fbba6]Marcos Salles[/b:f0a32fbba6], onde cada formulário se registra na ´fábrica´ de objetos. Só não gosto de uma coisa nesta abordagem: usar strings para identificar os forms, pois caso o nome seja digitado incorretamente o compilador não irá gerar nenhum aviso, por razões óbvias. Prefiro passar a definição classe que quero que a fábrica crie para mim.
Por fim, se quiser se aprofundar em design patters - algo extremamente aconselhável - visite os mesmos sites que indiquei acima, mas através destas URL´s:
http://www.oodesign.com.br/patterns/
http://www.dofactory.com/Patterns/Patterns.aspx
A diferença é que estes links levarão vc para a lista de todos os design patterns da GoF. Aliás, os exemplos do site [b:f0a32fbba6]oodesign [/b:f0a32fbba6]são os mesmos do [b:f0a32fbba6]Data & Object Factory[/b:f0a32fbba6], mas traduzidos para o português. Infelizmente nem todos os patterns constam na lista do site brasileiro ainda. Mas devem aparecer em breve.
[]´s
GOSTEI 0
Vitor Rubio
13/03/2006
Interessante isso, eu nunca tinha ouvido falar nessa técnica, e a clubedelphi 69 eu ainda não li. Eu tava dando uma olhada aqui no wikipédia, procurando por factory methods, e pelo que eu pude entender, na unit que você vai criar o factory method, no esqueleto dela, deve haver as condições para criação do objeto de cada classe. o método retorna o objeto criado, mas sua implementação precisa conhecer as classes, porque faz referenca a elas. Isso significa que a seção uses dessa unit vai crescendo a medida que o meu sistema cresce tambem.
Agora, vamos a um exemplo: e se eu coloco novas forms do meu software dentro de dll´s ou bpl´s que vão ser exibidas através de menus criados dinamicamente? eu não tenho essas units novas na seção uses do meu programa que já está rodando no cliente. Dá pra resolver isso também, ou nem tem haver com o que estamos conversando em si?
Agora, vamos a um exemplo: e se eu coloco novas forms do meu software dentro de dll´s ou bpl´s que vão ser exibidas através de menus criados dinamicamente? eu não tenho essas units novas na seção uses do meu programa que já está rodando no cliente. Dá pra resolver isso também, ou nem tem haver com o que estamos conversando em si?
GOSTEI 0
Marco Salles
13/03/2006
Mais tarde se voce ainda quiser eu lhe passo um exemplo
Agora duas coisas..
Não .. o interresante é que isto não é verdade.. Na uses onde esta declarado o metodo , não setem que declarar esses objetos
Mas voce pode gerar um aviso com um bloco try except , porque quando o nome esta errado uma exceção sera lançada
Agora duas coisas..
Eu tava dando uma olhada aqui no wikipédia, procurando por factory methods, e pelo que eu pude entender, na unit que você vai criar o factory method, no esqueleto dela, deve haver as condições para criação do objeto de cada classe. o método retorna o objeto criado, mas sua implementação precisa conhecer as classes, porque faz referenca a elas. Isso significa que a seção uses dessa unit vai crescendo a medida que o meu sistema cresce tambem.
Não .. o interresante é que isto não é verdade.. Na uses onde esta declarado o metodo , não setem que declarar esses objetos
Só não gosto de uma coisa nesta abordagem: usar strings para identificar os forms, pois caso o nome seja digitado incorretamente o compilador não irá gerar nenhum aviso, por razões óbvias.
Mas voce pode gerar um aviso com um bloco try except , porque quando o nome esta errado uma exceção sera lançada
GOSTEI 0
Marco Salles
13/03/2006
Mais tarde se voce ainda quiser eu lhe passo um exemplo
Agora duas coisas..
Não .. o interresante é que isto não é verdade.. Na uses onde esta declarado o metodo , não se declarar esses objetos.
Mas voce pode gerar um aviso com um bloco try except , porque quando o nome esta errado uma exceção sera lançada
Agora duas coisas..
Eu tava dando uma olhada aqui no wikipédia, procurando por factory methods, e pelo que eu pude entender, na unit que você vai criar o factory method, no esqueleto dela, deve haver as condições para criação do objeto de cada classe. o método retorna o objeto criado, mas sua implementação precisa conhecer as classes, porque faz referenca a elas. Isso significa que a seção uses dessa unit vai crescendo a medida que o meu sistema cresce tambem.
Não .. o interresante é que isto não é verdade.. Na uses onde esta declarado o metodo , não se declarar esses objetos.
Só não gosto de uma coisa nesta abordagem: usar strings para identificar os forms, pois caso o nome seja digitado incorretamente o compilador não irá gerar nenhum aviso, por razões óbvias.
Mas voce pode gerar um aviso com um bloco try except , porque quando o nome esta errado uma exceção sera lançada
GOSTEI 0
Vitor Rubio
13/03/2006
Se você puder mandar um exemplo bem basicão com classes de forms eu agradeço. Os exemplos que o site oodesign tinha pra download não foram suficientes pra me esclarecer totalmente.
Valew!
Valew!
GOSTEI 0
Marco Salles
13/03/2006
antes do exemplo so um comentário.. Ha uns tempos atrás eu participei com perguntas e posteriormente com respostas , sobre a criação de formulários passando o nome do form.. Porem , nada tecnico e sim usando sempre de artificios.. Porem isto me chamou a atençao e nas indas e vindas de pesquisa e procuras ,encontrei algo em design patterns..Isto antes da edição 69 do delphi ser editada. Porem veio um artigo nesta edição que fala do modelo de criaçao de objetos a patir de suas subclasses, que é basicamente o modelo de factory method. Li o artigo , porque gosto desta teorias , mas não me acrescentou nada de novo daquilo que ja conhecia ...Mas deixo aqui registrado , que o artigo é simples e foi muito bem editado Prof : Paulo Roberto Quicoli e mereçe os nosso singelos cumprimentos
Como foi dito anteriormente o modelo é muito simples , mas muito profundo em seus objetivos
Segue o exemplo na integra que pode ser baseado no artigo da ediçao 69 :
Crie uma Unit .. e declare o seguintes typo
para cada método escreva
Atente para esta função ...Uma exceçãopode ser lançada , quando o nome passado para a criação do formulario não fizer parte do Objetos da lista
[b:5d64ef4e0f]as funçoes são muito simples e entuitivas[/b:5d64ef4e0f]
Não esquecer de :
Ta , nossa interface para a criação de objetos esta toda definida... Slave a unit como achar melhor , se quiser adicional no seus projetos etc.. sirva-se a vontade
o macete agora e definir esta uses na aplicaçao Principal e Tb nos formularios que voce ira criar .. Por exemplo um form2
Com isso na compilação , é adicionado ao FList.AddObject o Nome e a classe do form... Isto é feito uma unica vez , para cada form que for registrado.. E depois com o proprio nome na hora de criar esse form , o Método TFormFactory.CreateForm é executado e ai se faz uma conversão ... Claro , que se o nome do form não existir na Lista de objetos uma exceção do tipo EAssertionFailed Sera lançada , que pode ser capturada e tratada , apesar do delphi suportar quase todas exceçoes
Por fim no formulario principal podemos fazer assim
Tudo igual da apostila com exceção do try except , para tratar
:arrow:
[b:5d64ef4e0f]Claro que o form2 esta na secção avalaibleForms[/b:5d64ef4e0f]
Então Vitor bom apetite...
Como foi dito anteriormente o modelo é muito simples , mas muito profundo em seus objetivos
Segue o exemplo na integra que pode ser baseado no artigo da ediçao 69 :
Crie uma Unit .. e declare o seguintes typo
unit Unit1; interface uses Forms, Classes, SysUtils, Controls;
type TFormFactory = class private FList: TStrings; public constructor Create; destructor Destroy; override; function CreateForm(const aFormName: string): TForm; procedure RegisterForm(const aFormName: string; aFormClass: TComponentClass); end;
function FormFactory: TFormFactory;
var _FormFactory: TFormFactory; { TFormFactory }
para cada método escreva
constructor TFormFactory.Create; begin inherited Create; FList := TStringList.Create; end;
Atente para esta função ...Uma exceçãopode ser lançada , quando o nome passado para a criação do formulario não fizer parte do Objetos da lista
function TFormFactory.CreateForm(const aFormName: string): TForm; var i : integer ; begin result := nil; i := FList.IndexOf(aFormName); Assert(i <> -1, ´Formulário ´+ aFormName +´ não existe´); Result := TComponentClass(FList.Objects[i]).Create(nil) as TForm; end;
destructor TFormFactory.Destroy; begin FList.Free; inherited; end;
[b:5d64ef4e0f]as funçoes são muito simples e entuitivas[/b:5d64ef4e0f]
procedure TFormFactory.RegisterForm(const aFormName: string; aFormClass: TComponentClass); var i: integer; begin i := FList.IndexOf(aFormName); if i = -1 then FList.AddObject(aFormName, TObject(aFormClass)); end;
function FormFactory: TFormFactory; begin result := _FormFactory; end;
Não esquecer de :
initialization _FormFactory := TFormFactory.Create; finalization _FormFactory.Free; end.
Ta , nossa interface para a criação de objetos esta toda definida... Slave a unit como achar melhor , se quiser adicional no seus projetos etc.. sirva-se a vontade
o macete agora e definir esta uses na aplicaçao Principal e Tb nos formularios que voce ira criar .. Por exemplo um form2
var Form2: TForm2; implementation uses FormFactoryU; //Nome da unit onde se tem os Métodos //Igual da apostila {$R *.dfm} initialization FormFactory.RegisterForm(´Form2´, TForm2); end.
Com isso na compilação , é adicionado ao FList.AddObject o Nome e a classe do form... Isto é feito uma unica vez , para cada form que for registrado.. E depois com o proprio nome na hora de criar esse form , o Método TFormFactory.CreateForm é executado e ai se faz uma conversão ... Claro , que se o nome do form não existir na Lista de objetos uma exceção do tipo EAssertionFailed Sera lançada , que pode ser capturada e tratada , apesar do delphi suportar quase todas exceçoes
Por fim no formulario principal podemos fazer assim
var Form1: TForm1; implementation uses FormFactoryU; {$R *.dfm}
Tudo igual da apostila com exceção do try except , para tratar
procedure TForm1.Button1Click(Sender: TObject); begin try FForm := FormFactory.CreateForm(´Form2´); FForm.ShowModal; FreeAndNil(FForm); except on EAssertionFailed do showmessage(´Nome errado´); end; end;
:arrow:
[b:5d64ef4e0f]Claro que o form2 esta na secção avalaibleForms[/b:5d64ef4e0f]
Então Vitor bom apetite...
GOSTEI 0
Vitor Rubio
13/03/2006
Andei meio ocupado então só agora pude ler e responder o tópico.
Cara, muito bom mesmo, muito útil e interessante. Só que se você comaprar com a solução que eu tinha pensado, verá que no fundo, não é muito diferente, a diferença é que o código do button1 deveria, logicamente, estar numa função que recebesse só o nome da form como parametro e devolvesse a form. Tambem do método que eu falei, vc trabalha soh com as classes e não com os objetos> se você olhar nos vontes da procedure registerclass, do delphi, vai encontrar uma estrutura parecida, em certo ponto, com a estrutura da classe TformFactory:
e o metodo RegisterClass(AClass) da variavel global reggroups:
obviamente, usando o factorymethod fica bem mais lógico e limpo. Vou começar a usar. Só tenho uma dúvida: para não precisar da fariavel global e da função qu acessa ela, os métodos para registrar a form e criar a form não poderiam ser métodos de classe?
Valew!
Cara, muito bom mesmo, muito útil e interessante. Só que se você comaprar com a solução que eu tinha pensado, verá que no fundo, não é muito diferente, a diferença é que o código do button1 deveria, logicamente, estar numa função que recebesse só o nome da form como parametro e devolvesse a form. Tambem do método que eu falei, vc trabalha soh com as classes e não com os objetos> se você olhar nos vontes da procedure registerclass, do delphi, vai encontrar uma estrutura parecida, em certo ponto, com a estrutura da classe TformFactory:
procedure RegisterClass(AClass: TPersistentClass); begin RegGroups.Lock; try while not RegGroups.Registered(AClass) do begin RegGroups.RegisterClass(AClass); if AClass = TPersistent then Break; AClass := TPersistentClass(AClass.ClassParent); end; finally RegGroups.Unlock; end; end;
e o metodo RegisterClass(AClass) da variavel global reggroups:
procedure TRegGroups.RegisterClass(AClass: TPersistentClass); var Group: TRegGroup; begin Group := FindGroup(AClass); if Group <> nil then Group.RegisterClass(AClass); end;
obviamente, usando o factorymethod fica bem mais lógico e limpo. Vou começar a usar. Só tenho uma dúvida: para não precisar da fariavel global e da função qu acessa ela, os métodos para registrar a form e criar a form não poderiam ser métodos de classe?
Valew!
GOSTEI 0