Qual maneira de destruir tabsheet com forms criados dinamica

Delphi

22/09/2005

olá pessoal

tenho no sistema uma tela onde crio tabsheets dinamicamente. Dentro de cada tabsheet é criado um form. Esse form cria dentro dele tb dinamicamento um segundo form e esse por sua vez cria outro form3.

então fico com uma cascata mais ou menos assim:
|TabSheet1  |  Tabssheet2 | ...
 |Form1|
   |Form2|
      |Form3|


Todos os forms são do tipo normal.

São criados assim:

...
// Tabsheet com o form1

        if TabSht = nil then
        begin
          TabSht               := TTabSheet.Create(Self);
          TabSht.Name          := ´TS´+IntToStr(CdCliente);
          TabSht.Caption       := NmCliente;
          TabSht.PageControl   := PgCtrlCliente;

          PgCtrlCliente.ActivePage := TabSht;

          frm1              := TFrm1F.Create(Self);
          frm1.Parent       := TabSht;
          frm1.Name         := ´frm1´+IntToStr(CdCliente);
          frm1.show;
        end;
...

{No Onshow do primeiro form1 eu crio o Form2}

  frm2 := TFrm2F.Create(self);
  frm2.Name   := ´frm2´+IntToStr(CdCliente);
  frm2.Parent := PnlProgs;
  frm2.show;

...

{E finalmente crio o form3 no form2.onshow}

  frm3 := TFrm3F.Create(self);
  frm3.Name   := ´frm3´+IntToStr(CdCliente);
  frm3.Parent := PnlProgs;
  frm3.show;
...



Assim terei varios tabsheets, um para cada cliente, sendo q através do findcomponent consigo saber os forms de um cliente para fechá-los e após excluir o tabsheet.

O que fiz mas acabou não dando certo, é no FormPrincipal que tem o pagecontrol com os tabsheets ter um botão Fechar. Nele está o código para ´fechar´ o tabsheet selecionado.

Implementei da seguinte maneira:

Fecho o form1 que está logo abaixo do tabsheet,
no evento form1.Onclosequery eu fecho o form2,
no envento form2.Onclosequery eu fecho o form3.

o código para fechar é o mesmo para todos e não tenho nos forms nenhuma rotina no evento Onclose.

...
{exemplo de como fecho o form1.. o codigo é o mesmo pra todos, só muda o form}

  if Self.FindComponent(´frm1´+IntToStr(CdCliente)) <> nil then
    TForm(Self.FindComponent(´frm1´+IntToStr(CdCliente))).Close;
...


então eu preciso fechar e liberar memória, observando que eu posso fechar esse cliente e criar ele novamente logo após.

e após fechar os forms, qual a maneira de excluir o tabsheet selecionado?


obrigado

Diogo


Diogoalles

Diogoalles

Curtidas 0

Respostas

Massuda

Massuda

22/09/2005

Talvez o mais fácil seja usar o mecanismo de Owner do Delphi.

Faça o Owner do frm1, frm2 e frm3 ser o TabSheet (ao invés de Self como você está fazendo) assim que o TabSheet é destruído ele se encarrega de destruir os forms.

qual a maneira de excluir o tabsheet selecionado
Pode fazer assim...
var
  Tab: TTabSheet; 
...
  Tab := PageControl1.ActivePage;
  if Tab <> nil then begin 
    PageControl1.ActivePageIndex := 0; 
    Tab.Free; 
  end; 
...
...note que você não pode excluir o TabSheet ativo.


GOSTEI 0
Diogoalles

Diogoalles

22/09/2005

Blz

Funcionou

Obrigado !


GOSTEI 0
Diogoalles

Diogoalles

22/09/2005

Massuda

To com problema com os forms q são criados.
Eu crio e fecho eles e sem fechar o form principal crio novamente, exatamente como está o meu codigo acima só que em vez de ´self´ coloco ´owner´ e em ambos os casos dá AV.

Acho q o problema está na criação dele para que ele seja destruido e criado novamente.

Poderia me ajudar?

obrigado
Diogo


GOSTEI 0
Massuda

Massuda

22/09/2005

...só que em vez de ´self´ coloco ´owner´...
Não entendi... será que dava para você postar aqui seu código?


GOSTEI 0
Diogoalles

Diogoalles

22/09/2005

Estou fazendo assim para criar os forms:

... 
// Tabsheet com o form1 

        if TabSht = nil then 
        begin 
          TabSht               := TTabSheet.Create(TabSht); 
          TabSht.Name          := ´TS´+IntToStr(CdCliente); 
          TabSht.Caption       := NmCliente; 
          TabSht.PageControl   := PgCtrlCliente; 

          PgCtrlCliente.ActivePage := TabSht; 

          frm1              := TFrm1F.Create(TabSht); 
          frm1.Parent       := TabSht; 
          frm1.Name         := ´frm1´+IntToStr(CdCliente); 
          frm1.show; 
        end; 
... 

{No Onshow do primeiro form1 eu crio o Form2} 

  frm2 := TFrm2F.Create(Owner); 
  frm2.Name   := ´frm2´+IntToStr(CdCliente); 
  frm2.Parent := PnlProgs; 
  frm2.show; 

... 

{E finalmente crio o form3 no form2.onshow} 

  frm3 := TFrm3F.Create(Owner); 
  frm3.Name   := ´frm3´+IntToStr(CdCliente); 
  frm3.Parent := PnlProgs; 
  frm3.show; 
...



Os forms estão em ´cascata´
Tenho o formPrincipal que tem o PageControl
O PageControl recebe os tabsheets
O tabsheet criado contém o form1
O form1 criado contém o form2
e o form2 contém o form3.

Para fechar faço o seguinte:
No formPrincipal tenho um botão que ´fecha´ o tabsheet ativo, antes de fehar o tabsheet ativo ele fecha os forms em cascata... 1º o form3, depois o form2 e depois o form1, por fim exclui o tabsheet.

...
// procedure Fechar Tabsheet

...
// a rotina para fechar o form3 está no form2.OncloseQuery
if Owner.FindComponent(´frm3´+IntToStr(CdCliente)) <> nil then
begin
  TForm(Owner.FindComponent(´frm3´+IntToStr(CdCliente))).Close;
  TForm(Owner.FindComponent(´frm3´+IntToStr(CdCliente))).Free;
end;
...

// a rotina para fechar o form2 está no form1.OncloseQuery
if Owner.FindComponent(´frm2´+IntToStr(CdCliente)) <> nil then
begin
  TForm(Owner.FindComponent(´frm2´+IntToStr(CdCliente))).Close;
  TForm(Owner.FindComponent(´frm2´+IntToStr(CdCliente))).Free;
end;

// e a rotina para fechar o form1 está no formPrincipal onde em seguida também é excluido o tabsheet.
if Owner.FindComponent(´frm1´+IntToStr(CdCliente)) <> nil then
begin
  TForm(Owner.FindComponent(´frm1´+IntToStr(CdCliente))).Close;
  TForm(Owner.FindComponent(´frm1´+IntToStr(CdCliente))).Free;
end;

// exclui o tabsheet selecionado após fechar seus forms parent.
TabSht := Frm550F.PgCtrlPac.ActivePage;
FreeAndNil(TabSht);
...


obrigado
Diogo


GOSTEI 0
Massuda

Massuda

22/09/2005

A princípio, acho que não tem necessidade de você ficar dando Close e Free nos foms que estão dentro do TabSheet pois eles serão destruídos junto com o TabSheet (lembre-se de por Action=caFree no OnClose dos forms).

Com relação ao AV, um modo disso acontecer seria o TabSht estar com valor não nil depois de você destruir o TabSheet. A variável TabSht é global?

Tenho a impressão de que a variável TabSht que aparece no trecho que fecha a TabSheet é uma variável local e não é a mesma que aparece na rotina que cria o TabSheet.


GOSTEI 0
Michael

Michael

22/09/2005

Olá colega!

Reparei nesta linha no seu código:

TabSht               := TTabSheet.Create(TabSht)


O Owner da TabSheet é ela mesma?

[]´s


GOSTEI 0
Diogoalles

Diogoalles

22/09/2005

Michael,
Não entendi bem essa questão do Owner, mas os tabsheets são criados dentor do pagecontrol que está localizado no formPrincipal.

a varável TabSht é global, declarada no form principal:

....
var
  Frm550F    : TFrm550F;
  TabSht     : TTabSheet;

implementation

uses ...
...



GOSTEI 0
Michael

Michael

22/09/2005

O [b:bb815e3229]Owner [/b:bb815e3229](proprietário, em inglês), é o componente que fica responsável por liberar outros pertencentes a ele da memória, quando este for destruído.

No seu código, eu notei que vc criou um TabSheet informando que o seu proprietário é ele mesmo. Teoricamente isto não é um erro, e até imagino que seja compilado, mas sinceramente não posso prever os efeitos desta abordagem durante a execução do código.

Uma dica: não use variáveis globais, pq não é uma maneira elegante de se programar. Se vc precisa que uma variável tenha um escopo maior, redeclare-as na seção Public ou Private do formulário, convertendo-as assim em campos da classe do form. É uma regra da etiqueta de programação. ;-)

[]´s


GOSTEI 0
Massuda

Massuda

22/09/2005

...Não entendi bem essa questão do Owner...
O que o Michael quis dizer é que é estranho um componente ter como Owner ele mesmo, mas o que acaba acontecendo é que durante a execução, no instante que a linha...
TabSht := TTabSheet.Create(TabSht);
...é executada, TabSht é nil, o que equivale a escrever...
TabSht := TTabSheet.Create(nil);


a varável TabSht é global, declarada no form principal:
Sendo assim, nos trechos que você postou não tem como ocorrer AV. Entretanto, observe que a função FindComponent [b:4feb070320]pode[/b:4feb070320] retornar nil, o que resultaria num AV.


GOSTEI 0
Michael

Michael

22/09/2005

...é executada, TabSht é nil, .


Tem razão Massuda.

De qualquer forma, não me agrada a idéia de se usar uma mesma variável em lugares diferentes do código, com funções diferentes. Fica difícil de se traçar o que está acontecendo.

[]´s


GOSTEI 0
Diogoalles

Diogoalles

22/09/2005

ô pessoal, me desculpem.. é que digitei errado e não estava entedendo o que estavam me dizendo:

não é isso:
TabSht := TTabSheet.Create(TabSht);


o CORRETO é esse:
TabSht := TTabSheet.Create(PgCtrlCliente); // é o pagecontrol o owner.


então só pra ver se entendi direito, a forma de criação dos forms dentro do tabsheet está correta?
não preciso nenhuma rotina de close e free para os forms? no caso é só eleminar o tabashhet ?

obrgiado

Diogo


GOSTEI 0
Massuda

Massuda

22/09/2005

...a forma de criação dos forms dentro do tabsheet está correta?
Pelo trecho que você postou, parece que sim.
...não preciso nenhuma rotina de close e free para os forms? no caso é só eleminar o tabashhet ?
Como o Owner de cada form (se eu entendi direito) é o TabSheet, então quando o TabSheet for destruído ele se encarregará de destruir os forms.


GOSTEI 0
POSTAR