Criação/Destruição de forms apenas pelo nome
13/03/2006
0
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
Posts
13/03/2006
Marco Salles
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
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
13/03/2006
Marco Salles
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
13/03/2006
Vitor Rubio
Gostaria de aprender mais sobre [b:30519434b0]Factory Method [/b:30519434b0], visto que nunca ouvi falar, nem sei o que é.
13/03/2006
Michael
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
13/03/2006
Vitor Rubio
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?
13/03/2006
Marco Salles
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
13/03/2006
Marco Salles
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
13/03/2006
Vitor Rubio
Valew!
13/03/2006
Marco Salles
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...
30/03/2006
Vitor Rubio
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!
Clique aqui para fazer login e interagir na Comunidade :)