Duduh_Capixaba Posted July 6, 2011 Report Share Posted July 6, 2011 Olá a todos!Estou criando formulários em tempo de execução da seguinte forma: busco em minha base de dados o nomedo formulário a ser criado e coloco em uma variável String. Abaixo está o código que estou usando.procedure TForm1.Button1Click(Sender: TObject); var vcls_form: TPersistentClass; vobj_form: TForm; nome_form: String; begin RegisterClass(TfrmTela1); RegisterClass(TfrmTela2); nome_form := tblFORM.FieldByName('DESCRICAO').AsString; vcls_form := GetClass(nome_form); if (Assigned(vcls_form)) and (vcls_form.InheritsFrom(TForm)) then begin vobj_form := TFormClass(vcls_form).Create(Self); vobj_form.Show; end; end;Com a String preenchida com o nome do form consigo criar o objeto sem problemas, mas com um porém:preciso registrar cada classe antes do comando GetClass, ou seja, cada nome de formulário existente no projeto.No meu teste registrei dois formulários: TfrmTela1 e TfrmTela2, mas em meu projeto tenho mais de 700 forms.Não gostaria de escrever essas 700 linhas, e nem ter que adicionar mais uma linha quando um novo form foradicionado ao projeto.Alguém teria uma outra idéia de como criar um obeto, passando como parâmetro uma variável String, sem sernecessário registrar classe por classe? Quote Link to comment Share on other sites More sharing options...
0 Jhonas Posted July 6, 2011 Report Share Posted July 6, 2011 veja o exemplohttp://www.delphibr.com.br/exemplos/Classref.ziphttp://www.delphibr.com.br/exemplos/OpClass.zipabraço Quote Link to comment Share on other sites More sharing options...
0 Duduh_Capixaba Posted July 8, 2011 Author Report Share Posted July 8, 2011 (edited) Olá Jhonas!Primeiramente obrigado pela resposta. Bem, eu rodei o exemplo CLASSREF, que é muito interessante.Já havia visto um exemplo parecido com esse, onde um formulário é criado antes dos outros objetos,código cedido pelo Micheus no forum da DevMedia.Os dois códigos me deram uma boa noção do que fazer, mas ainda não consegui chegar a uma solução.Deixe-me explicar melhor o problema:Tenho um projeto com vários formulários criados em modo de design. TfrmTela1, TfrmTela2, TfrmTela3,TfrmTela4... TfrmTela700. Esses formulários NÃO são criados na inicialização do aplicativo. Eles são criadosà medida que são chamados no projeto, e depois liberados da memória quando fechados. Ex.:O cliente clica no menu pra chamar o formulário 1:Application.CreateForm(TfrmTela1, frmTela1); frmTela1.Show;Quando ele fecha o formulário 1, o mesmo é liberado com um "Action := caFree". Ok! Tudo perfeito. Agoravamos à minha idéia...O que eu quero é o seguinte: passar para o código "Application.CreateForm(TfrmTela1, frmTela1)" parâmetrosSTRING. No caso, ficaria: Application.CreateForm('TfrmTela1', 'frmTela1').Por quê isso? Porque eu tenho em minha base de dados o nome de cada formulário do projeto. Sendo assimeu criaria uma procedure para criar os formulários buscando seu nome na base de dados.Eu até consegui esse feito usando o código que coloquei no primeiro post. Mas esse código tem um porém:eu preciso usar o comando "RegisterClass() e UnregisterClass()" em cada formulário, ou seja, teria que passarform por form (mais de 700) incluindo essas duas linhas de comando com o nome do formulário. Ou ainda, noformulário principal do projeto, registrar todos os forms de uma vez só e em seguida desregistrar, tendo quedigitar mais de 1500 linhas de código. E ainda por cima ter que incluir duas novas linhas no form principal a cadanovo form inserido no projeto.Gostaria de uma solução sem ter que utilizar o GetClass(), RegisterClass() e UnregisterClass(). Se tiver uma luzde como fazer isso me avise.Abraço Edited July 8, 2011 by Duduh_Capixaba Quote Link to comment Share on other sites More sharing options...
0 Micheus Posted July 9, 2011 Report Share Posted July 9, 2011 Tenho um projeto com vários formulários criados em modo de design. TfrmTela1, TfrmTela2, TfrmTela3, TfrmTela4... TfrmTela700. Esses formulários NÃO são criados na inicialização do aplicativo. Eles são criadosà medida que são chamados no projeto, e depois liberados da memória quando fechados.Observar que este procedimento está apenas manipulando as Instâncias e não as Classes de objetos definidas no projeto.É importante o entendimento sobre o que é Instância e Classe em OO (Orientação a Objetos).Na esquerda estão as instâncias da classe apresentada à direita. ref.: siteO que eu quero é o seguinte: passar para o código "Application.CreateForm(TfrmTela1, frmTela1)" parâmetrosSTRING. No caso, ficaria: Application.CreateForm('TfrmTela1', 'frmTela1').Isto é impossível!Entenda que o método CreateForm recebe como parâmetro dois endereços de memória. O primeiro se refere à definição da classe e o segundo à variável (passada por referência) que acomodará uma instância da referida classe.Assim, para criar uma instância de qualquer classe, nos termos que você gostaria, seria realmente necessário o uso de GetClass ou FindClass (métodos para os quais você passa como parâmetro o nome da classe (previamente registrada) e obtem sua "definição").Eu até consegui esse feito usando o código que coloquei no primeiro post. Mas esse código tem um porém:eu preciso usar o comando "RegisterClass() e UnregisterClass()" em cada formulário, ou seja, teria que passarform por form (mais de 700) incluindo essas duas linhas de comando com o nome do formulário.Você não precisa utilizar o UnregisterClass. No caso de a classe já ter sido registrada, uma nova chamada à RegisterClass não irá gerar problema algum - ela é suficientemente inteligente para isto. Está lá na documentação (help):If the class is already registered, RegisterClass does nothing. If a different class with the same name is already registered, RegisterClass raises an EFilerError exception.Deve ser lembrado que um programa em Delphi é compilado e não interpretado. O compilador Delphi otimiza o código de modo que uma variável declarada que não seja utilizada é removida do código final (executável) e o mesmo ocorre com as classes ("definições").Se voce tem adiconado ao seu projeto o arquivo que define um form (que é uma classe descendente de TForm), mas não faz uso explicitamente dele em lugar algum (tipo: CadProduto := TCadProduto.Create(self) ou Application.CreateForm(TCadProduto, CadProduto)), o compilador irá gerar o código final sem qualquer referência à esta classe de formulário, pois você não a está utilzando. Assim, ainda que você não queira criar uma instância explicitamente, mas queira criá-la dinamicamente da forma como foi colocada aqui neste tópico, então você tem que dizer para o compilador incluir a definição desta classe (do seu form) em seu executável. Somente desta forma ele terá condições de criar uma instância deste form em tempo de execução - conhecendo ele - por isto a necessidade de usar o RegisterClass.Quando você faz uso explícito da classe (como já exemplifiquei), o compilador automaticamente irá registrar a classe em questão. Isto também está no help para RegisterClass:"Form classes and component classes that are referenced in a form declaration (instance variables) are automatically registered."A estas alturas pode mesmo ser complicado/trabalhoso fazer os ajustes para 700 forms. Na análise do projeto, este dipo de coisa também já deveria ter sido pensada e assim ele cresceria sem causar transtornos.Na prática, qual seria o benefício esperado com esta abordagem?No meu entendimento (apenas minha opinião), se forem para: - Customizar a aplicação e ocultar opções entre diferentes clientes: bom, se for possível obter o nome das classes no executável, bastaria adicioná-la à tabela no banco de dados e lá estariam todas as telas disponíveis. - Economizar memória: a criação dinâmica dos forms e posterior liberação da memória (como feito usualmente ao remover os FormCreate do projeto) não consumiriam muito mais memória do que o modelo pretendido. - Criação de múltiplas instâncias de um mesmo form: (um form que cria uma nova instância de sua própia classe) Nesta modalidade, cuidados devem ser tomados quando utilizando utiliza-se componentes que referenciam outros forms/datasources (datasets, datasources, ...) - esta referência criada em design-time é traduzida pelo compilador de forma estática.Seguem algumas referências que podem ser úteis à algum dos leitores do tópico: - PROGRAMAÇÃO ORIENTADA A OBJETOS & DELPHI – Parte I – Uma Introdução sobre OO - Introdução ao Paradigma de Orientação a Objetos (artigo muito bom - vale a leitura) - Dynamic packages in Delphi (talvez a melhor forma de modularizar uma aplicação Delphi)Abraços Quote Link to comment Share on other sites More sharing options...
0 Duduh_Capixaba Posted July 11, 2011 Author Report Share Posted July 11, 2011 Olá, Micheus!Muito obrigado por sua explicação, me esclareceu muita coisa. Bem, pelo visto não tenho mesmo outrocaminho, senão o GetClass. Eu estava estudado sobre OO e agora percebo com mais clareza sua explicação.A minha ideia era customizar o código. Iria criar uma procedure para chamar as telas. Mas com o GetClasseu consegui o que queria, e acho que vou fechar mesmo nessa ideia.Muito obrigado, e até a próxima! Quote Link to comment Share on other sites More sharing options...
0 Micheus Posted July 11, 2011 Report Share Posted July 11, 2011 A minha ideia era customizar o código. Iria criar uma procedure para chamar as telas. Mas com o GetClass eu consegui o que queria, e acho que vou fechar mesmo nessa ideia.Voce ainda pode usar um função para este fim e apenas chamá-la passando alguns parâmetros e se você precisar utilizar o método Show ou ShowModal, talvez seja interessante passar um outro parâmetro para a função que cria o form (sugestão):procedure LoadForm(nome_form: string; owner: TComponent; is_modal :boolean); var vcls_form: TPersistentClass; vobj_form: TForm; begin vcls_form := GetClass(nome_form); if (Assigned(vcls_form)) and (vcls_form.InheritsFrom(TForm)) then begin vobj_form := TFormClass(vcls_form).Create(owner); if is_modal then vobj_form.ShowModal else vobj_form.Show; end else ShowMessage('Tentativa de carga de um formulário inválido ['+nome_form+'].'); end; Voce pode acrescentar o RegisterClass em cada unit do respectivo form utilizando a seção initialization (supostamente torna as coisas simples), como abaixo: unit uFrmTela1; type TfrmTela1 = class(TForm) ... end; procedure TfrmTela1.<evento>(...); begin ... end; initialization RegisterClass(TfrmTela1); end.Abraços Quote Link to comment Share on other sites More sharing options...
0 Jhonas Posted July 12, 2011 Report Share Posted July 12, 2011 Olá Micheus ... interessado em voltar a ser moderador ?? estamos precisando ... rsabraços Quote Link to comment Share on other sites More sharing options...
0 Micheus Posted July 12, 2011 Report Share Posted July 12, 2011 OFF: Fala Jhonas!estou só de passagem.De vez em quando me aparece uma MP e eu acabo dando uma voltinha por aqui. ;) Quote Link to comment Share on other sites More sharing options...
Question
Duduh_Capixaba
Olá a todos!
Estou criando formulários em tempo de execução da seguinte forma: busco em minha base de dados o nome
do formulário a ser criado e coloco em uma variável String. Abaixo está o código que estou usando.
Com a String preenchida com o nome do form consigo criar o objeto sem problemas, mas com um porém:
preciso registrar cada classe antes do comando GetClass, ou seja, cada nome de formulário existente no projeto.
No meu teste registrei dois formulários: TfrmTela1 e TfrmTela2, mas em meu projeto tenho mais de 700 forms.
Não gostaria de escrever essas 700 linhas, e nem ter que adicionar mais uma linha quando um novo form for
adicionado ao projeto.
Alguém teria uma outra idéia de como criar um obeto, passando como parâmetro uma variável String, sem ser
necessário registrar classe por classe?
Link to comment
Share on other sites
7 answers to this question
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.