2010-02-01 9 views
5

Me encontré con esta página Why shouldn’t I call Application​.CreateForm. Ahora tengo algo de código como este:¿Cómo evito llamar a Application .CreateForm dos veces?

SplashForm := TSplashForm.Create(Application); 
SplashForm.Show; 
SplashForm.Update; // force update 
Application.Initialize; 
Application.CreateForm(TClientData, ClientData); 
SplashForm.Update; // force update 
Application.CreateForm(TClientMainForm, ClientMainForm); 
Application.ShowHint := True; 

Application.Run; 
ClientMainForm.ServerConnected := false; 
FreeAndNil(ClientMainForm); 
FreeAndNil(ClientData); 

Primero un SplashForm se crea, a continuación, un módulo de datos y dura el formulario principal. La página dice que Application.CreateForm no debe ser llamado dos veces. ¿Debería cambiar el código anterior?

Saludos

Respuesta

5

No hay nada malo con el uso Application.CreateForm varias veces. Pero esto introduce variables globales para cada forma que pueden ser un olor a código. Desafortunadamente, el IDE crea uno para cada formulario. Aunque puedes eliminarlos si quieres.

Una forma mejor es crear un formulario cuando lo necesite y soltarlo cuando esté listo. Entonces solo usa Application.CreateForm para el formulario principal.

Se puede crear un módulo de datos principal mediante el formulario principal. Pero también puede ser global, solo una cuestión de gusto.

Para responder a la pregunta, puede evitar Application.CreateForm creando y liberando los formularios localmente.

El artículo menciona el efecto secundario de Application.CreateForm (el primer formulario completo es el formulario principal). Por lo tanto, puede haber efectos secundarios inesperados si el formulario principal crea otros formularios con Application.CreateForm.

Por lo tanto, para evitar cualquier desagradable, debe limitarse a una sola llamada. Lo cual se hace usando solo una forma global.

+0

no considero mejor estilo para eliminar el IDE creado globales . Esos son parte de cómo funcionan las aplicaciones Delphi. Tales "optimizaciones" son de hecho más un "olor a código" que un código generado IDE no optimizado. –

+4

@ Warren: Ese comentario no tiene ningún sentido. Con la única excepción de la variable de formulario principal, una aplicación Delphi no necesita hacer uso de * ninguna * de esas variables globales, y la de la forma principal podría ser reemplazada fácilmente por una variable en el archivo del proyecto, que no sería conocida por cualquier otra unidad, por lo que tampoco sería realmente una variable global. – mghie

+0

Simplemente estaba comentando la frase "Aunque puedes eliminarlos si quieres", no considero esa eliminación una buena idea. –

1

Si TClientData es un Módulo de datos y TClientMainForm es un formulario, entonces no (excepto quizás las dos llamadas de FreeAndNil al final, realmente no necesarias). Pero cuídate Porque como se dice Rob Kennedy en su puesto, el Application.CreateForm hace otras cosas detrás (que establece el MainForm variable), así que aconsejaría a configurar el archivo de proyecto de acuerdo con las siguientes reglas:

  1. Cree todos los formularios que desee crear en el inicio mediante una llamada única llamada a Application.CreateForm; generalmente esto lo hace el IDE.

  2. Eliminar del proyecto de presentar los formularios que desea crear dinámicamente (bajo demanda) en su programa. (En Proyecto | Opciones | Formas ...) - moverlos de 'Formas Auto-Crear' para '' Formularios disponibles

  3. Cree sus formas en su código usando TmyForm.Create (propietario) (etc. .) y no con Application.CreateForm (...). Como un aparte, si está seguro de que va a liberar el formulario, entonces es mejor (para acelerar las cosas) llamar al TmyForm.Create (nil) - sin propietario.

  4. Si desea hacer algún tipo de inicialización en el arranque puede tener un procedimiento/método en el archivo de proyecto atado a un módulo de formulario/datos ya creada y ejecutarlo antes de ejecutar la aplicación.

Por ejemplo:

begin 
    Application.Initialize; 
    Application.MainFormOnTaskbar := True; 
    Application.CreateForm(TdmoMain, dmoMain); //<--this is a data module 
    Application.CreateForm(TfrmMain, frmMain); //<--this will became the main form 
    Application.CreateForm(TfrmAbout, frmAbout); 
    //... other forms created here... 
    frmMain.InitEngine; //<--initialization code. You can put somewhere else, according with your app architecture 
    Application.Run; 
end. 

De esta manera tendrá el archivo de proyecto limpio y que sepa exactamente cuál es cuál.

HTH

+0

+1 La respuesta de PLAINTH explica y sigue las convenciones establecidas utilizadas por la mayoría de los desarrolladores de Delphi.Cualquier cosa que no sea eso viola lo que llamo el "principio de menor asombro". –

1

cuando escribí ese artículo, yo estaba pensando sobre todo de código fuera el archivo DPR. Las personas ven el código de creación de formularios generado por el IDE en el archivo DPR y piensan que esa es la mejor manera de crear formularios en general, por lo que lo usan en otros lugares de sus programas. A veces lo usan en el controlador de eventos OnCreate de la forma principal para crear otros formularios que su programa necesita, y luego tocan problemas porque la forma principal del programa no es lo que creen que es.

En el código que proporcionó, es fácil llamar a CreateForm solo una vez. Úselo para la forma principal, y para nada más. El módulo de datos no es una forma principal, por lo que no necesita la magia de CreateForm allí.

SplashForm := TSplashForm.Create(Application); 
SplashForm.Show; 
SplashForm.Update; // force update 
Application.Initialize; 

// Change to this. 
ClientData := TClientData.Create(Application); 

SplashForm.Update; // force update 
Application.CreateForm(TClientMainForm, ClientMainForm); 
Application.ShowHint := True; 

Application.Run; 
ClientMainForm.ServerConnected := false; 

// Remove these. 
FreeAndNil(ClientMainForm); 
FreeAndNil(ClientData); 

Realmente no debería liberar los objetos que ha creado aquí porque no los posee. Son propiedad del objeto Aplicación global, por lo tanto, deje que se encargue de liberarlos: elimine las dos llamadas a FreeAndNil.

+0

Si sabe que se ha creado el formulario principal, entonces otro formulario no puede convertirse mágicamente en el formulario principal. Si se comprende esa advertencia, entonces llamar a Application.CreateForm desde otro lugar que no sea su archivo fuente .dpr es una buena idea, si y solo si tiene la intención de que el objeto Aplicación gestione la vida de sus formularios desde ese momento en adelante. Sin embargo, como muchos de nosotros queremos formularios que vivan mientras viva la aplicación, y luego se liberen, este es exactamente el comportamiento deseado al llamar a Application.CreateForm. Lo llamo "creación tardía de formularios" y lo uso todo el tiempo. –

+1

El formulario principal puede ejecutar código propio antes de * designar como * el formulario principal. Ahí es donde ocurren los problemas. Si desea que el objeto Aplicación administre la duración, simplemente especifíquelo como el parámetro Propietario cuando llame al constructor de un formulario, tal como lo hace al crear cualquier otro objeto, y como lo demostré en el código en mi respuesta. ¿Por qué atribuirle importancia extra a la creación de un formulario cuando en realidad es lo mismo que crear una instancia de cualquier otra clase? El * único * motivo para llamar a CreateForm es cuando necesita Application.MainForm para establecerse. –

0

El artículo al que se refiere es incorrecto. Hay una serie de razones válidas por las que desea realizar varias llamadas a Application.CreateForm

1) Módulos de datos: probablemente desee que estén disponibles todo el tiempo. La mejor forma de hacerlo es Application.CreateForm. Sé de aplicaciones con varios módulos de datos temáticos, p. Cliente, Factura, Dirección para manejar diferentes áreas de la base de datos & encapsulan la funcionalidad cuidadosamente. Todos estos se crean en .dpr

2) Cosas grandes y lentas (lo cual es una mala idea en & en sí mismo, pero estas cosas suceden ya menudo son heredadas por programadores de soporte ...). Mueva el tiempo de carga al inicio de la aplicación exactamente como su código de ejemplo junto con la actualización de la pantalla de presentación. Los usuarios esperan aplicaciones a tomar un tiempo para ponerse en marcha gracias a los esfuerzos de nuestros colegas stirling que trabajan en Microsoft Office para bajar el listón de las expectativas para el resto de nosotros :)

Así, en resumen, no lo hacen te preocupa que tu código esté bien, pero puedes perder las cosas de "FreeAndNil". Por pequeño que golpear cosas de tipo de diálogo es el más rápido invocada por:

with TMyform.Create(nil) do 
try 
    //Setup 
    case ShowModal of 
    // Whatever return values you care about (if any) 
    end; 
finally 
    Free; 
end; 

corto, dulce, hasta el punto & minimiza el uso de la memoria ...

+0

Su afirmación de que el artículo vinculado es incorrecto es, de hecho, muy incorrecta. Ninguna de las * razones * que usted proporciona es una razón para llamar 'Application.CreateForm()', en absoluto. Re 1) simplemente puede 'Create()', pasando cualquier 'Owner' incluyendo' Application'. Re 2) puedes hacer eso primero en el evento 'OnCreate' del formulario principal, y nadie verá ninguna diferencia. – mghie

+1

Puede crear formularios de diferentes maneras, pero las formas en que lo describe implican tener que escribir un código adicional sin ganancia aparente. ¿Por qué querrías hacer las cosas deliberadamente de la manera "no Delphi"? Si crea un formulario o un módulo de datos en el IDE, Delphi le ayuda a crearlo en tiempo de ejecución mediante las sentencias Application.Createform que coloca en .dpr. En 16 años de trabajo con Delphi, aún no he visto ninguna evidencia de que Application.Createform sea intrínsecamente ineficaz o indeseable para los formularios que se necesitan durante el tiempo de vida de la aplicación, que parece ser la afirmación de los autores. – mcottle

Cuestiones relacionadas