Buen día,
Personalmente estoy de acuerdo con lo expresado por Roman en el post #9 del hilo que enlazo
aquí
Sin embargo hay una solucion que yo utilizo para evitar lidiar con los FreeAndNil, "releases" mal ubicados.
y es la siguiente:
1) Creo un Tform1 que es el MDIform y un tform2 que es el MDIChild
2) Elimino la variable automática que crea el Tform2 (form2), como sugiere ElKurgan
3) en el evento onclose del Tform2 agrego la linea: Action:= caFree;
4) Para efectos de la prueba agrego dos botones u opciones de menú en el form1.
a) el primer boton instancia formularios TForm2 sin asignarlos a variables (pues se liberarán con el Onclose.
Código Delphi
[-]procedure TForm1.NuevoFormulario1Click(Sender: TObject);
begin
With Tform2.Create(Self) do
Begin
inc(contador);
Caption:= IntTostr(contador);
show;
End;
end;
b) el segundo crea un formulario asignado a una única variable llamada MyFormX
Código Delphi
[-]procedure TForm1.formX1Click(Sender: TObject);
begin
if not Assigned(MyFormX) then
begin
MyFormX:= TForm2.Create(Self);
MyFormX.Show;
end else
MyFormX.BringToFront;
end;
PERO...!!! éste útlimo código solo funcionará una vez pues el Action:=caFree, libera la memoria pero la variable queda asignada por tanto Assigned(MyformX) solo será falso la primera vez...
entonces aqui utilizo un truco que me parece bastante seguro: Utilizo una variable de clase para indicar si el formulario está instanciado o no
Código Delphi
[-]unit Unit2;
type
TForm2 = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
public
Class var EstoyOcupado: String;
end;
y en el Form1 cambio el llamado al boton:
Código Delphi
[-]
procedure TForm1.formX1Click(Sender: TObject);
begin
if not Assigned(MyFormX) or (TForm2.EstoyOcupado <> 'SI') then
begin
MyFormX:= TForm2.Create(Self);
TForm2.EstoyOcupado:='SI';
MyFormX.Show;
end else
MyFormX.BringToFront;
end;
De ésta manera quedan asi los códigos
Form1:
Código Delphi
[-]
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus;
type
TForm1 = class(TForm)
MainMenu1: TMainMenu;
Nuevoform1: TMenuItem;
NuevoFormulario1: TMenuItem;
formX1: TMenuItem;
procedure NuevoFormulario1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure formX1Click(Sender: TObject);
private
public
contador: Integer;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses Unit2;
Var MyFormX: TForm2;
procedure TForm1.FormCreate(Sender: TObject);
begin
contador:=0;
end;
procedure TForm1.formX1Click(Sender: TObject);
begin
if not Assigned(MyFormX) or (TForm2.EstoyOcupado <> 'SI') then
begin
MyFormX:= TForm2.Create(Self);
TForm2.EstoyOcupado:='SI';
MyFormX.Show;
end else
MyFormX.BringToFront;
end;
procedure TForm1.NuevoFormulario1Click(Sender: TObject);
begin
With Tform2.Create(Self) do
Begin
inc(contador);
Caption:= IntTostr(contador);
show;
End;
end;
end.
Form2:
Código Delphi
[-]
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
type
TForm2 = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
public
Class var EstoyOcupado: String;
end;
implementation
{$R *.dfm}
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
TForm2.EstoyOcupado:='';
Action:= caFree;
end;
end.