Fórum Inibir duplicidade do Form na procedure #335300

27/12/2006

0

Pessoal,
Tenho uma aplicação onde uso Forms do tipo fsMDIChild
Entao para dar uma agilizada no trabalho gostaria de criar uma Procedure para criar os Forms de maneira mais pratica. Estou tentando fazer assim:


procedure Abre_Form_MDI( pTform : TFormClass; pForm : TForm  );
begin
  if pForm = nil then begin
    Application.CreateForm( pTform, pForm );
    pForm.Show;
  end;
end;



Eu faria chamada a esta procedure assim:

procedure TForm1.Cliente1Click(Sender: TObject);
begin
  Abre_Form_MDI( TForm2, Form2 );
end;



Esta tudo funcionando porem esta verificação na minha procedure:

if pForm = nil then begin


Nao esta funcionando, se eu chamar a procedure tres vezes .... tres vezes o form é aberto. Teria como resolver este problema??

Fico no aguardo.


Mmoreira

Mmoreira

Responder

Posts

27/12/2006

Tnaires

Olá
Para dar certo, você precisa atribuir [b:e906b99230]nil[/b:e906b99230] à variável que referencia o form assim que você o destruir. Porque, apesar do form ser destruído, a variável continua armazenando o endereço de memória no qual ele estava armazenado.
Abraços


Responder

Gostei + 0

27/12/2006

Mmoreira

tnaires,
Não entendi sua colocação, sera que voce poderia detalhar?


Responder

Gostei + 0

28/12/2006

Tnaires

OK
Quando você cria um form utilizando Application.CreateForm, você passa a classe do Form e a referência ( variável ) que o armazenará, certo?
A referência armazena o endereço de memória no qual o formulário está localizado. Quando você libera o formulário da memória, você destrói o objeto de fato, mas a variável continua apontando pra aquele endereço da memória que continha o formulário.
[b:564b17b224]Nil[/b:564b17b224] é uma constante do Delphi que pode ser associada a qualquer ponteiro ou referência. Quando uma referência aponta pra nil, na verdade não aponta pra nenhum endereço de memória.
Ou seja, para seu código dar certo, você tem que atribuir nil à variável que armazena o seu form quando você o destruir. Para isso, coloque sempre no OnClose dos seus forms:
Form1 := nil;

Onde Form1 é a referência ao form.
Lembre-se, isso não destrói o form! Para liberar o form da memória, use o método Release.
Outros colegas do fórum poderão corrigir algo que eu disse, ou complementar as informações.
Abraços


Responder

Gostei + 0

28/12/2006

Mmoreira

tnaires,

Estou usando a procedure:

procedure TForm1.Cliente1Click(Sender: TObject); 
begin 
  Abre_Form_MDI( TForm2, Form2 ); 
end;



Para criar o Form2, tenho nos enventos deste Form os codigos:

procedure TForm2.FormDestroy(Sender: TObject);
begin
  Form2 := nil;
end;




procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;



O meu problema é que mesmo o Form2 ja estando criado se eu executar a procedure -

Abre_Form_MDI( TForm2, Form2 ); 


- o sistema cria novamente o Form2 ... e vai criando quantas vezes eu a chamar. O meu problema na verdade é que quando eu faço a verificação:

if pForm = nil then begin


Não esta funcionando


Responder

Gostei + 0

28/12/2006

Mmoreira

tnaires,

Se voce tiver um tempo da uma olhada neste exemplo e vai ver o que esta acontecendo:

http://www.sendspace.com/file/c7b2qp


Responder

Gostei + 0

28/12/2006

Macario

Olá [b:b20dea39b6]mMoreira[/b:b20dea39b6], tranquilo?


Então veja da seguinte maneira :arrow: :


[b:b20dea39b6]procedure Abre_Form_MDI( pTform : TFormClass; pForm : TForm );
begin
if not Assigned(pForm) then
Application.CreateForm( pTform, pForm );
pForm.Show;
end;[/b:b20dea39b6]

Esper que ajude. 8)


Responder

Gostei + 0

28/12/2006

Mmoreira

Macario,

Fiz a mudança sugerida por voce:

procedure Abre_Form_MDI( pTform : TFormClass; pForm : TForm  );
begin
  if not Assigned(pForm) then begin
    Application.CreateForm( pTform, pForm );
    pForm.Show;
  end;
end;



Aconteceu o mesmo problema!!


Responder

Gostei + 0

28/12/2006

Macario

Olá.

Eu faço uso do Assigned para criar meus Forms, mas pelo visto isto não funciona com Forms do tipo fsMDIChild.


Responder

Gostei + 0

28/12/2006

Tnaires

O Assigned verifica justamente se o ponteiro aponta pra nil. O help do Delphi sugere que
if Assigned(Ponteiro)

e
if Ponteiro = nil

é a mesma coisa. Se não for, alguém poderia apresentar as diferenças?

mMoreira, vi seu projeto e achei o problema.
Quando você cria o primeiro form, seu endereço é armazenado na variável.
Quando você cria o segundo form, a variável contém o endereço do primeiro form, que está sendo exibido na tela. Ou seja, a condição pForm = nil nunca vai ser verdadeira enquanto você tiver alguma outra instância do mesmo form sendo mostrada na tela.
Possíveis soluções:
- escrever uma rotina que percorra todos os forms abertos e verifique se não existe alguma outra instância dele já criada;
- utilizar forms SDI ( modais ).

Abraços


Responder

Gostei + 0

28/12/2006

Fortaum

- Olá... experimente isso após fechar o form:
FreeAndNil(NomedoForm);

sds!


Responder

Gostei + 0

28/12/2006

Tnaires

Possíveis soluções: - escrever uma rotina que percorra todos os forms abertos e verifique se não existe alguma outra instância dele já criada; - utilizar forms SDI ( modais ).


Caro mMoreira, se você quer exibir apenas um form de cada vez, porque você tá usando MDIChild?


Responder

Gostei + 0

28/12/2006

Macario

Acredito que seja por facilidade tipo:

Acessar o Cadastro de Cliente e tambem o Cadastro de Fornecedor ao mesmo tempo por exemplo.

Mas não quer que se tenha mais de um cadastro de cliente aberto.


Responder

Gostei + 0

28/12/2006

Mmoreira

É isso mesmo pela facilidade de poder trabalhar com varias telas de cadastro ao mesmo, poder alternar entre as telas.

Agora pessoal vejam isso:

Criando os Forms atravez da minnha procedure que esta assim:

  if pForm = nil then begin
    Application.CreateForm( pTform, pForm );
    pForm.Show;
  end;


Chamei a procedure 3 vezes ... ou seja criei o mesmo Form 3 vezes. Ai no Form1 eu estou fazendo isso:

procedure TForm1.nomes1Click(Sender: TObject);
var
  i : integer;
begin
  for i := 0 to MDIChildCount - 1 do begin
    ShowMessage( MDIChildren[i].Name );
  end;
end;



Eu tenho tres mensagens:

1 - Form2_1

2 - Form2_2

3 - Form2


O nome esta sendo alterado por isso minha condição nao funciona


Responder

Gostei + 0

28/12/2006

Tnaires

Mas não quer que se tenha mais de um cadastro de cliente aberto.

Ah sim, entendi.

O nome esta sendo alterado por isso minha condição nao funciona

A qual condição você está se referindo? A comparação com nil?


Responder

Gostei + 0

28/12/2006

Mmoreira

tnaires,

Nao estava me referindo ao nil, na verdade eu acabei falando besteira dei uma viajada legal!!! Ja estou ficando doido com isso. De acordo com o que voce disse uma solução seria verificar quais forms estao abertos e fazer a comparação para saber se poderia ou nao ser criado o form.

Um colega aqui do forum me passou um dodigo mas o mesmo deveria ficar na unit principal do aplicativo. O codigo dele ficou assim:

Função para sazer se o form ja existe:

function TForm1.FormAberto(AForm: TFormClass): Boolean;
var
  i: Integer;
begin
  Result := false;
  for I := 0 to  MDIChildCount - 1 do
    if MDIChildren[i].ClassType = AForm then
    begin
      Result := true;
      Break;
    end;
end;



Procedure que vai criar o Form:

procedure TForm1.Abre_Form_MDI( pTform : TFormClass; pForm : TForm  );
begin
  if FormAberto(pTform) then
    Exit
  else
  begin
    Application.CreateForm( pTform, pForm );
    pForm.Show;
  end;
end;



Chamada a procedure:

procedure TForm1.Cliente1Click(Sender: TObject);
begin
  Abre_Form_MDI( TForm2, Form2 );
end;



Tudo certo ... apesar de estar funcionando perfeitamente nao me atende 100¬ pois eu gostaria de deixar isso em uma Unit de funcoes de sistema que tenho com varias outras. Entao para contornar isso eu alterei o codigo desta maneira entao ficou tudo na minha Unit de funcoes:

Função para sazer se o form ja existe:

function FormAberto(AForm: TFormClass; pForm_Principal : TForm): Boolean;
var
  i: Integer;
begin
  Result := false;
  for I := 0 to  pForm_Principal.MDIChildCount - 1 do
    if pForm_Principal.MDIChildren[i].ClassType = AForm then
    begin
      Result := true;
      Break;
    end;
end;



Procedure que vai criar o Form:
procedure Abre_Form_MDI( pTform : TFormClass; pForm_Cria, pForm_Principal : TForm );
begin
  if FormAberto(pTform, pForm_Principal) then
    Exit
  else
  begin
    Application.CreateForm( pTform, pForm_Cria );
    pForm_Cria.Show;
  end;
end;




Chamada a procedure:
procedure TForm1.Cliente1Click(Sender: TObject);
begin
Abre_Form_MDI( TForm2, Form2, Form1 );
end;


Entao é isso ai, para evitar que ficasse na unit principal do sistema tive que passar como parametro o Form1 que tem sua propriedade:

Form1.FormSyle := fsMDIForm



Acho que nao da para simplificar isso ai mais .... ou será que dá ????


De qualquer forma fica ai meu agradecimento a todos que me ajudaram.

Valewww!!



Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar