2010-10-16 12 views
5

Ho un modulo principale (padre) MDI e un modulo figlio MDI. Creo il bambino in fase di esecuzione in questo modo:"Impossibile creare il modulo. Nessun modulo MDI è attualmente attivo" Errore

VAR 
    FrmDereplic: TFrmDereplic; 

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

Procedura per riprodurre l'errore:
comincio l'applicazione, si preme il pulsante per creare il bambino, premo il tasto 'x' sulla principale (genitore) modulo per chiudere l'applicazione e ottengo un errore "Impossibile creare il modulo. Nessun modulo MDI è attualmente attivo".

La linea su cui compare l'errore è nel form figlio:

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; 

risparmio un sacco di proprietà del form (e di altre proprietà controlli) al file INI. Ma fallisce solo quando provo a salvare fltExtensions.ItemIndex (che è un TFilterComboBox). Se commento quella linea funziona perfettamente.

Qualche idea del motivo per cui tenta di creare un modulo quando ho effettivamente chiuso l'applicazione ?????????

risposta

6

Guardo alcuni siti Web e ho appena trovato il problema. Sembra che sia meglio se il proprietario è l'applicazione, non il modulo principale. Remy Lebeau suggerisce che il vero problema è nell'OnDestroy della forma infantile. Non esiste un handle valido per la finestra che contiene il filtro, quindi viene chiamato OnDestroy. Quindi, cambiare l'ordine di distruzione dà una possibilità a TFrmDereplic.OnDestroy per eseguire correttamente.

Quindi, ecco la soluzione:

SOLUZIONE (S)

FrmDereplic:= TFrmDereplic.Create(Application);

o

Do not save form's properties in OnDestroy

Il secondo richiede poche righe in più di codice come l'OnClose ancora è non sempre chiamato. Questo è stato estratto da Delphi AIUTO:

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

Se si utilizza Application.Terminate, quindi onCloseQuery e onClose non sarà chiamato. Lo stesso per Halt (ma ... è troppo estremo, vero?).

2

Se il codice che hai fornito nella tua domanda è quello vero allora credo che l'errore è in questa linea:

FrmDereplic:= TFrmDereplic.Create(TMainFrm); 

non ho mai provato questo e io non sono sicuro se il compilatore compra davvero (può testarlo ora), ma stai provando a impostare una classe come proprietario del modulo figlio MDI. Invece di che si dovrebbe fare uno

FrmDereplic:= TFrmDereplic.Create(Application); 

o

FrmDereplic:= TFrmDereplic.Create(self); 

La prima opzione consente di impostare l'applicazione in qualità di titolare del form figlio MDI, mentre il secondo pone l'istanza del modulo principale MDI come proprietario .

Spero che questo aiuti.:-)

+2

L'OP è arrivata a questa conclusione tre ore prima che tu facessi il tuo post. –

+0

@Andreas - Volevo contrassegnare il mio post come risolto ma StackOverflow mi fa attendere 2 giorni. Comunque, è bello che altre persone confermino la mia soluzione. Significa che è buono. – Ampere

+2

@ Vicens - Siamo spiacenti. È infatti MainForm invece di TMainForm. Ho inserito l'errore quando ho digitato il codice. Nel mio codice il modulo ha un nome diverso. Ho cambiato il suo nome in MainForm per rendere il codice più facile da capire (modulo principale = il genitore del modulo figlio). Ancora una volta mi dispiace. Si prega di notare che il sé non funzionerà !! In realtà è equivalente al mio codice originale (buggy). Perché? Perché Self = MainForm. – Ampere

3

L'errore si verifica durante la lettura della proprietà fltExtensions.ItemIndex perché richiede fltExtensions avere un HWND, che richiede il suo genitore forma TFrmDereplic avere un HWND, che richiede MainForm del progetto di avere un HWND. Ma l'applicazione è in uno stato di arresto e il MainForm non può più allocare il suo HWND, quindi TFrmDereplic genera un'eccezione quando non è in grado di ottenere un HWND per se stesso.

Il salvataggio dei dati INI nell'evento OnDestroy è troppo tardi. È necessario invece l'evento OnClose.

+0

Ma OnClosed viene saltato in alcune situazioni. Ciò significa che i dati non verranno salvati su disco! La mia attuale implementazione funziona. È sbagliato? Posso usarlo così com'è? Immagino che usando Application come proprietario di quella forma cambi la sequenza di distruzione. Ciò dà a TFrmDereplic la possibilità di eseguire OnDestroy correttamente. – Ampere

+1

OnClose viene chiamato quando si chiude l'app con la maggior parte dei mezzi: pulsante X sulla finestra, TForm.Close(), Application.Terminate(), ecc. Ma sì, ci sono alcune situazioni in cui OnCose non viene sempre chiamato, ma tali condizioni possono essere gestito separatamente Puoi refactoring il tuo codice di salvataggio nella sua funzione che è possibile chiamare da più posti quando necessario. Per quanto riguarda il motivo per cui il codice stesso è sbagliato, ho già spiegato che - OnDestroy è in genere troppo tardi per accedere ai valori delle proprietà basati su HWND, come ItemIndex. L'impostazione di Applicaton come proprietario ha semplicemente permesso al figlio MDI di essere distrutto prima del MainForm. –

+0

"Per quanto riguarda il motivo per cui il codice stesso è sbagliato, ho già spiegato che" - Scusa, mi riferivo al nuovo codice in cui l'ho risolto impostando l'Applicazione (anziché MainForm) come Proprietario. Se questo compito è valido, preferirei usarlo invece di rinunciare a OnClose. – Ampere

Problemi correlati