PDA

Ver la Versión Completa : Como abrir forms dentro de otro form


anubis
15-08-2016, 02:11:39
Hola amigos,

Como he visto que en varios post preguntando lo mismo para lazarus, voy a aportar lo que he recogido y resumido de otros post.

En primer lugar colocamos en el form principal un panel vacio, en la propiedad align le asignais alClient.

Si queremos que, al pulsar un boton, se abra el form debeis poner:

procedure TPrincipal.SpkLargeButton8Click(Sender: TObject);
begin
if not assigned(fproveedores) then //Para verificar que no ha sido asginado/abierto el form y no lo abra mas de una vez.
begin
fproveedores:=tfproveedores.Create(application);
fproveedores.Parent:=panel; //Asignamos parent al panel para que se abra dentro de él.
fproveedores.Show;
end;
end;

En las propiedades del form que queremos abrir, le tenemos que asignar:
align:=alNone
BorderStype:=bsSizeable
FormStyle:=fsNormal

En el evento OnClose del form le poneis fproveedores.nil, para que quede desasignado y podamos abrirlo despues.

Con eso ya nos abrira el form dentro del panel.

Una puntualizacion adicional.
Como en mi caso tengo algun problema a la hora de maximizar o cambiar el tamaño porque no refresca bien, lo que hice fue, meter en la clausula uses del form, vinculo con el form principal asi, a la hora de hacer un onResize, haga un refresh del panel.

procedure Tfproveedores.FormResize(Sender: TObject);
begin
principal.contenedor.refresh;
end;


Espero que a alguien le sirva este pequeño resumen.

Gracias

Casimiro Notevi
15-08-2016, 11:15:13
Fproveedores.nil
Eso no libera la memoria, debes hacer Fproveedores.Free

AgustinOrtu
15-08-2016, 18:44:38
Tiene owner el objeto Application. Así que se destruye al final de todo. Así que en la práctica es un memory leak porque está la referencia al form hasta que no se destruye Application.

Básicamente se crea un form nuevo cada vez que se dispara el evento del botón. Y cuando se cierra queda oculto y como la referencia original es nil, not assigned evalúa a true

Lo suyo es evitar las variables globales; crear, mostrar, operar el form, y destruirlo cuando no se necesita más. Como cualquier objeto, por ejemplo cuando se usan stream siempre se liberan cuando ya no hace falta

Ahora es cierto que hay casos en los que un form, frame o cualquier control se incrusta dentro de otro y el tiempo de vida es el mismo que el de su parent. En ese caso lo ideal es crearlos en el constructor y destruirlos en el destructor. Lo mismo que un dbgrid, un string grid, un ListView, etc. Código que anda chequeando por nil termina cansando
Lo justo es asegurarse de que todo los controles estén propiamente inicializados.

Por ejemplo en tu código no preguntas si el botón esta asignado. Así debería ser siempre con todos

dec
15-08-2016, 18:47:53
Hola,

[...]Código que anda chequeando por nil termina cansando [...]


¡De acuerdo en todo y en lo citado! :)

anubis
16-08-2016, 22:58:19
Gracias por las respuestas.
Teneis toda la razon y ademas aplastante.
La idea de poner solo form.nil, es porque si meto form.free en el evento onclose como recomedabais, a la hora de cerrar el formulario da error de violacion. entiendo que estas intentando liberar un formulario creado desde el mismo sitio que lo estas cerrando asi que no entiendo entonces donde se debe de poner.
Por otro lado amigos, nose si hay alguna forma de saber si un formulario esta abierto (no asignado) para poder meter en ese punto el form.free.

Perdonad la ignorancia, de momento no he usado nunca los constructores, pero veo que es diferente a crearlos.:(.

Sobre asignar el boton que abre el formulario ademas, quiero pensar, del form asignado, como le digo que el boton esta asignado para que no deje pulsarlo mas veces, si tengo que tener en cuenta que lo debe de desasignar cuando el formulario se cierre?

AgustinOrtu
16-08-2016, 23:35:12
En el OnClose le pones Action caFree y el framework ya se encarga de liberarlo.

Ese AV se produce porque luego de ejecutar tu evento TForm sigue haciendo algunas cosas en su método DoClose

ecfisa
17-08-2016, 04:09:07
...
Por otro lado amigos, nose si hay alguna forma de saber si un formulario esta abierto (no asignado) para poder meter en ese punto el form.free.

Hola Anubis.

Si para determinar si el formulario está abierto o cerrado, usas el modo

if not Assigned(fproveedores) then
begin
fproveedores := Tfproveedores.Create(...);
...

o, con el mismo resultado:

if fproveedores = nil then
begin
fproveedores := Tfproveedores.Create(...);
...

No te va a alcanzar con liberar el segundo formulario, también deberás poner el valor nil en la variable (fproveedores) al cerrarlo o destruirlo.

Tal vez estos enlaces te aclaren mas el punto:

FreeAndNil VS Free (http://www.clubdelphi.com/foros/showthread.php?t=73190)
Cómo detectar si un formulario ya está abierto? (http://www.clubdelphi.com/foros/showthread.php?t=72311)


Saludos :)

anubis
18-08-2016, 01:54:10
Se agradece.

Entonces si le añado como decis, en el evento onclose del formulario fproveedores, closeaction:=cafree, y luego fproveedores:=nil, ya no estoy dejando sin cerrarlo y encima liberarlo.