[Lazarus-es] Dudas varias II

JoshyFun joshyfun en gmail.com
Sab Jun 20 13:43:44 CEST 2009


Hello Bruno,

Saturday, June 20, 2009, 3:19:30 AM, you wrote:

BL> Compilo ok ahora y ejecuto
BL> pero al hacer click en el menu clientes
BL> Project raised exception 'External  : SIGSEGV'
BL> Esto es lo que ejecuta el click de menu:
BL> procedure TForm1.clientesClick(Sender: TObject);
BL> begin
BL>   FormCli.showmodal;
BL> end;

A ver, hay una gran diferencia entre definir un form, esto es sus
controles y comportamiento, y otra instanciarlo. Haciendo el uses xxx;
lo que haces es incluir la definición del form clientes en el form que
estés usando, pero nada más, por decirlo de otro modo "FormCli" apunta
a una zona de memoria indeterminada y por lo tanto erronea.

Cámbialo por:

procedure TForm1.clientesClick(Sender: TObject);
var
  InstancedFormCli: TFormCli;
begin
  InstancedFormCli:=TFormCli.Create(Self);
  InstancedFormCli.showmodal;
  InstancedFormCli.Free;
end;

Resumiendo el código, creas una copia de la definición de FormCli
llamada "InstancedFormCli" (como si le quieres llamar Juan), después
le dices que la instancia (inicialice), luego que la muestre en modo
modal, y al final que la libere.

Existe cierta tendecia malsana de la gente que viene de los primeros
Delphi y de otros lenguajes tipo VB a crear todos los formularios en
el arranque pero dejándolos invisibles y luego mostrarlos y ocultarlos
según convenga. Esto es un gasto de recursos brutal en algunos casos.
Un form sólo definido ocupa unos 4 bytes de memoria, instanciado puede
ocupar megas.

Cada vez que defines un form, tanto delphi como Lazarus crean una
variable global que es una definición del form (4 bytes), que verás en
el código del form, después del "type", más abajo, verás "var FormCli:
TFormCli", eso se usa para que Lazarus pueda crear una instancia de
ese form automáticamente nada más arrancar si así se lo mandas. Esto
va bien si tienes que tener sólo una instancia de cada form, pero muy
mal por que hace creer al programador que esa es la única instancia
posible del form.

Para ponerte un ejemplo, la función de arriba cámbiala por:

procedure TForm1.clientesClick(Sender: TObject);
var
  InstancedFormCli: TFormCli;
  Count: SizeInt;
begin
  for Count:=1 to 20 do begin
    InstancedFormCli:=TFormCli.Create(Self);
    InstancedFormCli.Show;
  end;
end;

Lazarus te ha creado 20 forms iguales pero independientes y encima has
perdido el control individual de cada uno de ellos, ya que
InstanceFormCli sólo apunta al último. Puedes cerrarlos todos uno a
uno, pero si cierras el principal (Form1) verás que los cierra todos
de golpe, ya que Lázarus si sabe cuales están abiertos (lo apunta
internamente).

Resumiendo, suele ser una buena técnica de programación no usar la
variable que define el form por defecto excepto en el form principal o
en el caso seguro de que no van a existir más de una representación de
ese form a lo largo de todo el programa. Aún así no debemos olvidarnos
de comprobar si debemos instanciarlo cada vez que queramos mostrarlo.
Una buena técnica que suele simplificar esto cuando usamos ShowModal
habitualmente es:

procedure TForm1.clientesClick(Sender: TObject);
begin
  if not Assigned(FormCli) then begin
    FormCli:=TFormCli.Create(Self);
  end;
  FormCli.ShowModal;
  FreeAndNIL(FormCli);
end;

De este modo si el form está instanciado, lo muestra y después lo
libera. Si no está instanciado, lo instancia, lo muestra y lo libera.

-- 
Best regards,
 JoshyFun





More information about the Lazarus-es mailing list