Как при закрытии формы ее же и уничтожить?
Модератор: Модераторы
Как при закрытии формы ее же и уничтожить?
Это не главная форма приложения.
Код: Выделить всё
procedure TForm2.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
CloseAction := caFree;
end;Но очень часто после добавления этой строчки возникают Access Violation. Поэтому надо быть осторожным с вызовами уже уничтоженных объектов!
А можно так:
Код: Выделить всё
frm_test := Tfrm_test.Create(Application);
frm_test.ShowModal;
if frm_test.Free <> nil then frm_test.Free;Извиняюсь за отсутствие. Уточню свой вопрос.
Формы открываются немодально.
Существует, по сути, МДИ приложение. Пользователь может открыть произвольное число форм. Соответственно, в произвольном порядке может закрывать их.
>А разве при Close форма не уничтожается?
При закрытии форма не уничтожается. Надо отдельно сделать Free().
> CloseAction := caFree;
Пробовал. Выдает сообщение об ошибке. Пробовал последней строкой в OnClose() уничтожать саму себя. Тоже сообщение об ошибке.
Пока что реализовал следующим образом. Сделал что-то наподобие панели окон (как в Опере или 1С). При закрытии окна добавляю форму в список форм для уничтожения. При отрисовке панели окон уничтожаю эти формы.
Пока корявовато. Отрисовка происходит необязательно, нельзя быть уверенным, что после закрытия форма уничтожена.
А в чем смысл:
>if frm_test.Free <> nil then frm_test.Free;
По моему, эта строка в корне неверна. Во-первый, Free - это процедура а не функция, во вторых frm_test<>nil - это не гарантия, что форма существует и Free может вызвать ошибку.
Формы открываются немодально.
Существует, по сути, МДИ приложение. Пользователь может открыть произвольное число форм. Соответственно, в произвольном порядке может закрывать их.
>А разве при Close форма не уничтожается?
При закрытии форма не уничтожается. Надо отдельно сделать Free().
> CloseAction := caFree;
Пробовал. Выдает сообщение об ошибке. Пробовал последней строкой в OnClose() уничтожать саму себя. Тоже сообщение об ошибке.
Пока что реализовал следующим образом. Сделал что-то наподобие панели окон (как в Опере или 1С). При закрытии окна добавляю форму в список форм для уничтожения. При отрисовке панели окон уничтожаю эти формы.
Пока корявовато. Отрисовка происходит необязательно, нельзя быть уверенным, что после закрытия форма уничтожена.
А в чем смысл:
>if frm_test.Free <> nil then frm_test.Free;
По моему, эта строка в корне неверна. Во-первый, Free - это процедура а не функция, во вторых frm_test<>nil - это не гарантия, что форма существует и Free может вызвать ошибку.
- Sergei I. Gorelkin
- энтузиаст
- Сообщения: 1409
- Зарегистрирован: 24.07.2005 14:40:41
- Откуда: Зеленоград
Вообще говоря, у форм существует метод Release, позволяющий "безопасно" ее уничтожить. "Безопасно" - означает, что запрос на уничтожение ставится в очередь и исполняется после завершения возможного выполнения всех обработчиков событий этой формы.
Однако CloseAction := caFree; приводит к вызову Release сразу же после OnClose.
Однако CloseAction := caFree; приводит к вызову Release сразу же после OnClose.
tria писал(а):Пробовал. Выдает сообщение об ошибке.
Если MDI форма при caFree выдаёт ошибку, то это уже баг, надо оформлять...
tria писал(а):По моему, эта строка в корне неверна. Во-первый, Free - это процедура а не функция, во вторых frm_test<>nil - это не гарантия, что форма существует и Free может вызвать ошибку.
Строка бессмысленна, т.к. Free специально сделана для безопасного вызова деструктора. Она должна проверять существование объекта. Однако, я слишком часто натыкаюсь, что FPC реализация сделана на живую нитку...
- Сергей Смирнов
- энтузиаст
- Сообщения: 595
- Зарегистрирован: 28.04.2005 13:23:25
- Откуда: Москва
- Контактная информация:
tria писал(а):Извиняюсь за отсутствие. Уточню свой вопрос.
Формы открываются немодально.
Существует, по сути, МДИ приложение. Пользователь может открыть произвольное число форм. Соответственно, в произвольном порядке может закрывать их...
Вот эту http://freepascal.ru/article//lazarus/20050523080000/ статью читали? Вроде бы там похожий случай описан.
Вот именно!Atrus писал(а):Если MDI форма при caFree выдаёт ошибку, то это уже баг, надо оформлять...
А в чем смысл:
>if frm_test.Free <> nil then frm_test.Free;
По моему, эта строка в корне неверна. Во-первый, Free - это процедура а не функция, во вторых frm_test<>nil - это не гарантия, что форма существует и Free может вызвать ошибку.
Опечатался я -) Бывает.
Предлагаемый вариант звучит так:
Код: Выделить всё
frm_test := Tfrm_test.Create(Application);
frm_test.ShowModal;
if frm_test <> nil then frm_test.Free;>Sergei I. Gorelkin
Спасибо за обстоятельный ответ.
>Если MDI форма при caFree выдаёт ошибку, то это уже баг, надо оформлять...
В Лазаре MDI формы еще не реализованы. При попытке присвоения FormStyle:=fsMDIchild выдает ошибку '...MDI forms not implemented yet'. Все мои проблемы как раз от этого.
Ошибка вылетает на обычной форме.
>Вот эту http://freepascal.ru/article//lazarus/20050523080000/ статью читали? Вроде бы там похожий случай описан.
В статье предполагается, что работает CloseAction := caFree;, а у меня почему-то после этого возникает ошибка.
Это только у меня одного? У кого-то такой код работает?
И еще из статьи:
"Все объекты приложения должны иметь уникальные имена" - это условие правильности работы любого LCL приложения? (в примере в статье при невыполнении этого условия не будет работать код
(Application.FindComponent(FormName) as TForm).SetFocus)
На Делфи у меня это условие не выполнялось и все нормально работало...
Спасибо за обстоятельный ответ.
>Если MDI форма при caFree выдаёт ошибку, то это уже баг, надо оформлять...
В Лазаре MDI формы еще не реализованы. При попытке присвоения FormStyle:=fsMDIchild выдает ошибку '...MDI forms not implemented yet'. Все мои проблемы как раз от этого.
Ошибка вылетает на обычной форме.
>Вот эту http://freepascal.ru/article//lazarus/20050523080000/ статью читали? Вроде бы там похожий случай описан.
В статье предполагается, что работает CloseAction := caFree;, а у меня почему-то после этого возникает ошибка.
Это только у меня одного? У кого-то такой код работает?
И еще из статьи:
"Все объекты приложения должны иметь уникальные имена" - это условие правильности работы любого LCL приложения? (в примере в статье при невыполнении этого условия не будет работать код
(Application.FindComponent(FormName) as TForm).SetFocus)
На Делфи у меня это условие не выполнялось и все нормально работало...
Atrus писал(а): Free специально сделана для безопасного вызова деструктора. Она должна проверять существование объекта. Однако, я слишком часто натыкаюсь, что FPC реализация сделана на живую нитку...
Может я какой-то неправильный, но у меня и в Делфи применение Free к уже уничтоженному объекту ВСЕГДА приводило к ошибке.
- Сергей Смирнов
- энтузиаст
- Сообщения: 595
- Зарегистрирован: 28.04.2005 13:23:25
- Откуда: Москва
- Контактная информация:
Работать не будет даже создание формы с именем, идентичным имени уже существующей формы. Я точно не уверен, но думаю, что это обязательное условие и для дельфи. Иначе RTTI работать не сможет. Сейчас, кажется, именование создаваемых форм вручную уже не требуется, т.к. LCL научили это делать самостоятельно.tria писал(а):В статье предполагается, что работает CloseAction := caFree;, а у меня почему-то после этого возникает ошибка.
Это только у меня одного? У кого-то такой код работает?
И еще из статьи:
"Все объекты приложения должны иметь уникальные имена" - это условие правильности работы любого LCL приложения? (в примере в статье при невыполнении этого условия не будет работать код
(Application.FindComponent(FormName) as TForm).SetFocus)
На Делфи у меня это условие не выполнялось и все нормально работало...
В своё время я бодался с разработчиками по поводу встраивания форм в панель как временной замены MDI. Там были (и, наверное, так и остались) глюки и различия в работе в винде и линухе. Однако, то ли меня не поняли, то ли решили, что я хочу странного. В общем эта тема подвисла, хотя и всплывает с некоторой периодичностью в разных видах. В большинстве случаев исправление такого рода глюков относят на post 1.0.
В общем, пока нашел следующее:
В простом приложении CloseAction := caFree работает нормально.
У меня не работало в ситуации:
f1 - предок, f2-потомок.
Заработало так:
Однако, при закрытии приложения вылетает на:
В модуле Application.inc
На формах множество компонент, созданных динамически. Контроля за тем, чтобы имена были разными я не делал. Проект портирован с Делфи, там все работало.
В простом приложении CloseAction := caFree работает нормально.
У меня не работало в ситуации:
f1 - предок, f2-потомок.
Код: Выделить всё
f1.FormClose()
begin
CloseAction := caFree
end;
f2.FormClose()
begin
Inherited;
... - делаем действия
end;
Заработало так:
Код: Выделить всё
f2.FormClose()
begin
... - делаем действия
Inherited;
end;
Однако, при закрытии приложения вылетает на:
Код: Выделить всё
procedure TApplication.FreeComponent(Data: PtrInt);
begin
TComponent(Data).Free;
end;В модуле Application.inc
На формах множество компонент, созданных динамически. Контроля за тем, чтобы имена были разными я не делал. Проект портирован с Делфи, там все работало.
Для того чтоб не возникало проблем с уничтоженными объектами лучше всего использовать процедуру
она равносильна выполнению (например для оъекта Form1)
вызов метода Free или Destroy выполняет освобождение памяти распределенной под данный объект, но не выполняют заNILение переменной которая ссылаеться на этот кусок памяти. Данная особенность относиться и к FPC. Проверка на nil используеться в функции Assigned() (и методе Free). Это основная функция для проверки доступности объекта. Но так как проверка на nil проходит, то возникают эти трудно уловимые AV (Access Violation).
Поэтому настоятельно рекомендую использовать что то наподобии
В свое время я сам долго искал методы проверки доступности объекта но к сожалению нашел только функцию Assigned, но при грамотном подходе ее вполне достаточно.
Код: Выделить всё
FreeAndNil()она равносильна выполнению (например для оъекта Form1)
Код: Выделить всё
Form1.Free;
Form1 := nil;вызов метода Free или Destroy выполняет освобождение памяти распределенной под данный объект, но не выполняют заNILение переменной которая ссылаеться на этот кусок памяти. Данная особенность относиться и к FPC. Проверка на nil используеться в функции Assigned() (и методе Free). Это основная функция для проверки доступности объекта. Но так как проверка на nil проходит, то возникают эти трудно уловимые AV (Access Violation).
Поэтому настоятельно рекомендую использовать что то наподобии
Код: Выделить всё
var
frm: TForm1;
begin
if Assigned(frm) then
FreeAndNil(frm)
else
begin
frm := TForm1.Create(Application);
frm....
....
end; В свое время я сам долго искал методы проверки доступности объекта но к сожалению нашел только функцию Assigned, но при грамотном подходе ее вполне достаточно.
