2010-10-16 4 views
5

У меня есть основная (родительская) форма MDI и дочерняя форма MDI. Я создаю ребенок во время выполнения, как это:«Невозможно создать форму. В настоящее время нет форм MDI» Ошибка

VAR 
    FrmDereplic: TFrmDereplic; 

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

Шагов для воспроизведения ошибки:
я запустить приложение, жму на кнопку, чтобы создать ребенок, я нажимаю на кнопку «х» на главное (родительский) формы, чтобы закрыть приложение, и я получаю сообщение «Невозможно создать форму. В настоящее время MDI-формы не активны».

Линия, на которой появляется ошибка в дочерней форме:

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; 

я экономлю много свойств формы (и других контролируют свойства) в файл INI. Но он только терпит неудачу, когда я пытаюсь сохранить fltExtensions.ItemIndex (который является TFilterComboBox). Если я прокомментирую эту строку, она отлично работает.

Любая идея, почему она пытается создать форму, когда я фактически закрыл приложение ?????????

ответ

6

Я смотрю на некоторых веб-сайтах и ​​только что нашел проблему. Похоже, лучше, если Владелец - это Приложение, а не основная форма. Реми Лебо предполагает, что реальная проблема заключается в OnDestroy дочерней формы. В окне, где хранится фильтр, нет действительного дескриптора, который вызывается OnDestroy. Таким образом, изменение порядка уничтожения дает возможность TFrmDereplic.OnDestroy выполнить правильно.

Итак, вот решение:

РЕШЕНИЕ (S)

FrmDereplic:= TFrmDereplic.Create(Application);

или

Do not save form's properties in OnDestroy

Второй требует несколько дополнительных строк кода, как OnClose даже является не всегда называется. Это была извлечена из Delphi HELP:

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

Если вы используете Application.Terminate, то OnCloseQuery и OnClose не будет называться. То же самое для Halt (но ... это слишком экстремально, не так ли?).

2

Если код содержится в вашем вопросе является реальной, то я предполагаю, что ошибка в этой строке:

FrmDereplic:= TFrmDereplic.Create(TMainFrm); 

Я никогда не пробовал это, и я не уверен, что если компилятор действительно покупает (может 't проверить его сейчас), но вы пытаетесь установить класс как владельца дочерней формы MDI. Вместо того, что вы должны сделать что-либо

FrmDereplic:= TFrmDereplic.Create(Application); 

или

FrmDereplic:= TFrmDereplic.Create(self); 

Первый вариант устанавливает приложение в качестве владельца дочерней формы MDI, в то время как второй один задает экземпляр основной формы MDI в качестве владельца ,

Надеюсь, что это поможет.:-)

+2

ОП пришел к такому выводу за три часа до того, как вы сделали свой пост. –

+0

@Andreas - Я хотел отметить свое сообщение как решенное, но StackOverflow заставляет меня ждать 2 дня. Во всяком случае, приятно, что другие люди подтверждают мое решение. Это значит, что это хорошо. – Ampere

+2

@ Vicens - Извините. Это действительно MainForm вместо TMainForm. Я ввел ошибку, когда набрал код. В моем коде форма имеет другое имя. Я изменил его имя на MainForm, чтобы сделать код более понятным (основная форма = родительская дочерняя форма). Еще раз извините. Обратите внимание, что Self не будет работать! Это фактически эквивалентно моему оригинальному (багги) коду. Зачем? Потому что Self = MainForm. – Ampere

3

Ошибка возникает при чтении fltExtensions.ItemIndex свойства, поскольку он требует fltExtensions иметь HWND, которая требует его родительского TFrmDereplic формы, чтобы иметь HWND, который требует MainForm проекта иметь HWND. Но приложение находится в состоянии выключения, и MainForm больше не может назначить свой HWND, поэтому TFrmDereplic вызывает исключение, когда он не может получить HWND для себя.

Сохранение данных INI в форме OnDestroy. Событие слишком поздно. Вместо этого вам необходимо выполнить событие OnClose.

+0

Но OnClosed пропускается в некоторых ситуациях. Это означает, что данные не будут сохранены на диске! Моя текущая реализация работает. Это неправильно? Могу ли я использовать его так, как есть? Я предполагаю, что использование приложения в качестве владельца этой формы изменяет последовательность уничтожения. Это дает возможность TFrmDereplic правильно выполнить OnDestroy. – Ampere

+1

OnClose вызывается при закрытии приложения большинством способов - кнопка X в окне, TForm.Close(), Application.Terminate() и т. Д. Но да, есть ситуации, когда OnClose не всегда вызывается, но эти условия могут обрабатываться отдельно. Вы можете реорганизовать свой код сохранения в свою собственную функцию, которую вы можете вызывать из нескольких мест, когда это необходимо. Что касается того, почему сам код ошибочен, я уже объяснил, что - OnDestroy обычно слишком поздно для доступа к значениям свойств на основе HWND, например ItemIndex. Установка Applicaton as Owner просто позволила ребенку MDI быть уничтоженным до MainForm. –

+0

«Что касается того, почему сам код неправильный, я уже объяснил это» - Извините, я имел в виду новый код, где я исправил его, установив приложение (вместо MainForm) в качестве владельца. Если это назначение действительно, я предпочел бы использовать его вместо отказа от OnClose. – Ampere

Смежные вопросы