2010-10-16 8 views
5

Tengo un formulario MDI principal (principal) y un formulario secundario MDI. Creo que el niño en tiempo de ejecución así:"No se puede crear formulario. No hay formularios MDI actualmente activos" error

VAR 
    FrmDereplic: TFrmDereplic; 

procedure TMainFrm.Button2Click(Sender: TObject); 
begin 
FrmDereplic:= TFrmDereplic.Create(MainFrm); 
FrmDereplic.Show; 
end; 

Pasos para reproducir el error:
comienzo a la aplicación, pulsar el botón para crear el niño, pulsar el botón de 'x' en la principal (padre) formulario para cerrar la aplicación y aparece el mensaje "No se puede crear formulario. No hay formularios MDI actualmente activos".

La línea en la que aparece el error está en el formulario secundario:

procedure TFrmDereplic.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
Action:= caFree; 
end; 

procedure TFrmDereplic.FormDestroy(Sender: TObject); 
VAR MyIniFile: TCubicIniFile; 
begin 
MyIniFile:= TCubicIniFile.Create(AppINIFile); 
TRY 
    with MyIniFile DO 
    begin 
    if WindowState<> wsMaximized then 
    begin 
    // save form's screen pos 
    ... 
    end; 
    WriteInteger ('Dereplicator', 'fltExtensions', fltExtensions.ItemIndex); <----- HERE 
FINALLY 
    FreeAndNil(MyIniFile); 
END; 
end; 

puedo guardar un montón de propiedades del formulario (y propiedades de otros controles) en el archivo INI. Pero solo falla cuando intento guardar fltExtensions.ItemIndex (que es un TFilterComboBox). Si comento esa línea, funciona perfectamente.

¿Alguna idea de por qué intenta crear un formulario cuando realmente cerré la aplicación ?????????

Respuesta

6

Miro en algunos sitios web y acabo de encontrar el problema. Parece que es mejor si el propietario es la aplicación, no el formulario principal. Remy Lebeau sugiere que el verdadero problema está en el OnDestroy de la forma del niño. No hay un identificador válido para la ventana que contiene el filtro, entonces se llama a OnDestroy. Entonces, cambiar el orden de destrucción le da la oportunidad a TFrmDereplic.OnDestroy de ejecutarse correctamente.

lo tanto, aquí está la solución:

SOLUCIÓN (S)

FrmDereplic:= TFrmDereplic.Create(Application);

o

Do not save form's properties in OnDestroy

El segundo requiere pocas líneas adicionales de código que el OnClose siquiera es no siempre llamado. Este fue extraído de Delphi AYUDA:

Note: When the application shuts down, the main form receives an OnClose event, but any child forms do not receive the OnClose event.

Si utiliza Application.Terminate, entonces onCloseQuery y onClose no serán llamados. Lo mismo ocurre con Halt (pero ... esto es demasiado extremo, ¿no?).

2

Si el código que ya ha proporcionado en su pregunta es el verdadero entonces creo que el error está en esta línea:

FrmDereplic:= TFrmDereplic.Create(TMainFrm); 

Nunca he intentado esto y no estoy seguro de si el compilador realmente lo compra (puede 't probarlo ahora), pero está tratando de establecer una clase como propietario de la forma secundaria MDI. En lugar de que usted debe hacer, ya sea

FrmDereplic:= TFrmDereplic.Create(Application); 

o

FrmDereplic:= TFrmDereplic.Create(self); 

La primera opción establece la aplicación como propietario del formulario secundario MDI, mientras que la segunda establece la instancia del formulario principal MDI como propietario .

Espero que ayude.:-)

+2

El OP llegó a esta conclusión tres horas antes de que realizara su publicación. –

+0

@Andreas - Quería marcar mi publicación como resuelta pero StackOverflow me hace esperar 2 días. De todos modos, es bueno que otras personas confirmen mi solución. Significa que es bueno. – Ampere

+2

@ Vicens - Lo siento. De hecho, es MainForm en lugar de TMainForm. Ingresé el error cuando escribí el código. En mi código, el formulario tiene un nombre diferente. Cambié su nombre a MainForm para hacer que el código sea más fácil de entender (formulario principal = el padre del formulario hijo). Lo siento de nuevo. Tenga en cuenta que Self no funcionará. En realidad es equivalente a mi código original (con errores). ¿Por qué? Porque Self = MainForm. – Ampere

3

El error se produce cuando se lee la propiedad fltExtensions.ItemIndex porque requiere fltExtensions tener un HWND, lo que requiere su forma TFrmDereplic padres para tener un HWND, lo que requiere MainForm del proyecto para tener un HWND. Pero la aplicación se encuentra en estado de cierre y MainForm ya no puede asignar su HWND, por lo que TFrmDereplic genera una excepción cuando no puede obtener un HWND por sí mismo.

Guardar su información INI en el formulario OnDestroy es demasiado tarde. Necesita el evento OnClose en su lugar.

+0

Pero OnClosed se omite en algunas situaciones. ¡Lo que significa que los datos no se guardarán en el disco! Mi implementación actual funciona. ¿Esta mal? ¿Puedo usarlo tal como es? Supongo que usar Application como propietario de esa forma cambia la secuencia de destrucción. Esto le da la oportunidad a TFrmDereplic de ejecutar correctamente OnDestroy. – Ampere

+1

Se llama a OnClose al cerrar la aplicación por la mayoría de los medios: botón X en la ventana, TForm.Close(), Application.Terminate(), etc. Pero sí, hay algunas situaciones en las que OnClose no siempre se llama, pero esas condiciones pueden ser manejado por separado. Puede refactorizar su código de ahorro en su propia función que puede llamar desde múltiples lugares cuando sea necesario. En cuanto a por qué el código en sí es incorrecto, ya expliqué que - OnDestroy suele ser demasiado tarde para acceder a valores de propiedad basados ​​en HWND, como ItemIndex. Establecer Applicaton como Owner simplemente permitió destruir el hijo MDI antes de MainForm. –

+0

"En cuanto a por qué el código en sí es incorrecto, ya expliqué que" - Lo siento, me refería al nuevo código donde lo he arreglado estableciendo la aplicación (en lugar de MainForm) como propietario. Si esta tarea es válida, preferiría usarla en lugar de renunciar a OnClose. – Ampere

Cuestiones relacionadas