Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Уничтожение родительской формы [D7, WinXP]


Страницы:   1 2

Alex Kryuchkov ©   (2006-10-09 14:19:00) 

Добрый день!

Есть МДИ-приложение. Пусть его главная форма называется ФОРМА1.
В нём имеется ФОРМА2, которая вяляется МДИ-потомком ФОРМЫ1.

А на ФОРМЕ2 расположена ФОРМА3, то есть ФОРМА3.parent=ФОРМА2,
ФОРМА3.owner=ФОРМА2,

Пусть на ФОРМЕ3 есть КНОПКА.
По нажатию этой кнопки выполняется уничтожение ФОРМЫ2, т.е
FORM2.Free;

Так вот, если так делать, то получим Access Violation, что естественно, так как ФОРМА2 пытается уничтожить ФОРМУ3, а та как раз выполняет обработку сообщения нажатия на кнопку.
В документации по Делфи написано, что так делать нельзя.

НО!

Если мы перед уничтожением ФОРМЫ3 покажем какой-нибудь месседж, то ошибки не увидим:

procedure TForm3.Button1Click(Sender: TObject);
begin
 Showmessage('сообщение');
 Form2.Free;
end;

Аналогичный эффект будет, если соответствующим образом переопределить деструктор ФОРМЫ2.

Внимание вопрос
Почему так происходит? И как избежать ошибки без отображения сообщения?

Проблема состоит в том, что имеется достаточно большое приложение, в котором есть похожий код и отказаться от такой схемы нельзя.


RASkov   (2006-10-09 21:35:00) [1]

> пример иллюстрирует работу очень сложного и большого приложения


> была допущена ошибка


> Именно поэтому хотелось бы узнать, как можно решить проблему
> каким-нибудь "обходным путем"

procedure TForm3.Button1Click(Sender: TObject);
begin
Showmessage('Извените, форма закрывается!');
Form2.Free;
end;

Лишняя "ошибка" в ошибочном коде, думаю не навредит:)
Ну мож там слип какойнить или еще чего вместо сообщения...
Это - если это не помогает: PostMessage(Handle, CM_RELEASE, 0, 0);Т.е. Form2.Release;
Я англ не понимаю, но помоему здесь написано то что надо:
Release does not destroy the form until all event handlers of the form and event handlers of components on the form have finished executing. Release also guarantees that all messages in the form's event queue are processed before the form is released. Any event handlers for the form or its children should use Release instead of Free(Delphi) or delete (C++). Failing to do so can cause a memory access error.


Ketmar   (2006-10-09 18:06:00) [2]

>[30] Игорь Шевченко(c) 9-Oct-2006, 17:34
>GC собственно ни к чему.
можно и без него, конечно. но с ним проще, и багов меньше. %-)


Alex Kryuchkov   (2006-10-09 17:58:00) [3]

Отвечаю на Shirson ©   (09.10.06 17:15) [25]

Естественно, Ваш код будет работать без ошибок - ведь OWNER у Form3 при таком коде - Application и удаление формы2, если я не ошибаюсь, не вызовет удаления формы3.

В моем же коде такая связь есть и убрать я её не могу (точнее, это очень трудно)


Германн   (2006-10-09 17:57:00) [4]


> Все определяется литражом пива, а вовсе не видом :)

Интересно какой литраж в свое время пришлось выставить АП за право ходить в синих? :-)


Игорь Шевченко   (2006-10-09 17:45:00) [5]

MsGuns ©   (09.10.06 17:35) [31]


> Лишнее подтверждение тому, что голубые штаны выдают не только
> за умный вид


Все определяется литражом пива, а вовсе не видом :)


MsGuns   (2006-10-09 17:35:00) [6]

>Игорь Шевченко ©   (09.10.06 17:19) [27]
>Я придерживаюсь несколько иных принципов - а именно, что формы (не важно, дочки они или мамы) должны только отображать данные и реагировать на действия пользователя. А логикой (включая логику отображения форм) все-таки должны заниматься специальные классы, которые не подозревают о существовании форм.

Ну дык.. Лишнее подтверждение тому, что голубые штаны выдают не только за умный вид ;)))


Игорь Шевченко   (2006-10-09 17:34:00) [7]

Ketmar ©   (09.10.06 17:21) [29]

GC собственно ни к чему.


Плохиш   (2006-10-09 17:21:00) [8]


> Shirson ©   (09.10.06 17:15) [25]

Создай два экземпляра TForm2 и получишь AV с вероятностью 98%.


Ketmar   (2006-10-09 17:21:00) [9]

>[27] Игорь Шевченко(c) 9-Oct-2006, 17:19
ах, если бы в Delphi сразу вделали GC. и написали бы VCL по нормальной схеме "model-controller-view"... мечты, мечты...


Игорь Шевченко   (2006-10-09 17:19:00) [10]

MsGuns ©   (09.10.06 17:15) [26]

Я придерживаюсь несколько иных принципов - а именно, что формы (не важно, дочки они или мамы) должны только отображать данные и реагировать на действия пользователя. А логикой (включая логику отображения форм) все-таки должны заниматься специальные классы, которые не подозревают о существовании форм.


MsGuns   (2006-10-09 17:15:00) [11]

5. При реализации общего функционала в "маме" исключать обращения к экземплярам кдасса "дочек" (это вообще дурной метод, приводящий к большим проблемам при оиладке и глюкам при работе приложений), активно используя Sender и контроль типа "инициатора", вызвавшего то или иное событие (действие), а также сво-во "мамы" ActiveMDIChild. Это поможет избежать исключений и непоняток при отладке, хоть иногда и приводит к некоторой кажущейся избыточности кода

ЗЫ. Я вообще считаю, что лучше написать 200 "лишних" строк, проверяющих корректность кода, чем в погоне за "оптимальностью" допустить вероятность сбоя - хотя Зотов с Шевченко меня бы за это бы и обложил матюгами ;))


Shirson   (2006-10-09 17:15:00) [12]

procedure TForm2.FormCreate(Sender: TObject);
begin
Application.CreateForm(TForm3, Form3);
Form3.Parent:=Form2;
Form3.Show;
end;

procedure TForm3.Button1Click(Sender: TObject);
begin
Form2.free; // Form2.Release; тоже функционирует.
end;

Всё работает - форма прилежно умирает, без вскриков.


Ketmar   (2006-10-09 17:14:00) [13]

>[23] MsGuns(c) 9-Oct-2006, 17:07
ну да. примерно это я и имел в виду в [19]. только расписывать так чётко лень. %-)


MsGuns   (2006-10-09 17:07:00) [14]

В свое время были проблемы с MDI-программированием.
После внимательного прочтения Тексейры и освоения некоторых основных правил построения MDI-интерфейса все проблемы испарились.
Вот основные принципы проектирования MDI:

1. Главная форма (она же является и "владелицей" и "родительницей" всех "дочек посредством своей клиентской области) должна содержать максимум функционала и переменных общего назначения. В том числе элементов управления (кнопки, меню, подменю и т.д. - реализованные через ОБЩИЙ TActionList, TImageList). Обработчики акций должны обращаться к "дочкам" через ActiveMDIForm, определяя их тип либо посылать посредством сообщений.
2. "Дочки" должны работать независимо друг от друга, общаясь только с "мамой". Т.е. если одна "дочка" должна передать другой "дочке" что-либо, то делается это строго через "маму" посредством "маминых" же объектов  (переменные, структуры, массивы и т.д.) либо сообщениями.
3. "Дочки" должны содержать только специфический для их класса функционал и минимум элементов управления. Элементы управления могут находиться как на самих "дочках", так и интегрироваться с общим "маминым" управляющим интерфейсом.
4. Если приложение работает с БД, то не должно быть "дочек", разделяющих общие датасеты (не путать с таблицами !)


Ketmar   (2006-10-09 17:07:00) [15]

>[21] Alex Kryuchkov 9-Oct-2006, 17:04
>предложенный в [18] способ работать не будет.
почему? вообще -- в курсе отличий Free() и Release()? отцы рекомендуют, кстати, именно последний метод. более того, у отцов он работает. может, всё-таки руки как-то не так встали? %-)


Alex Kryuchkov   (2006-10-09 17:04:00) [16]

Сергей М.,
предложенный в [18] способ работать не будет. Более того, и не работает.

Что ты можешь сказать о том, что АВ не летит, если выводить перед вызовом деструктора сообщение?

Если невнимательно читал вопрос, повторяю еще раз:

procedure TForm3.Button1Click(Sender: TObject);
begin
Showmessage('сообщение');
Form2.Free; //AV нет
end;


procedure TForm3.Button1Click(Sender: TObject);
begin
Form2.Free; //AV есть
end;


Сергей М.   (2006-10-09 16:59:00) [17]


> Alex Kryuchkov   (09.10.06 16:55) [17]


А что тебе сказать "конструктивного", если MDI тобой упомянут всуе, ибо не имеет НИ малейшего отношения к "проблеме" ?

см. [18]


Ketmar   (2006-10-09 16:58:00) [18]

а вообще, имо, тут надо менеджер форм делать. который и будет заведовать убийствами/рождениями. а ему командовать через PostMessage(). %-)


clickmaker   (2006-10-09 16:56:00) [19]

procedure TForm3.Button1Click(Sender: TObject);
begin
Form2.Release;
end;


Alex Kryuchkov   (2006-10-09 16:55:00) [20]

Сергей М., Shirson дал совершенно правильный ответ [2] на твой вопрос.

Что теперь ты можешь сказать конструктивного?


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо