Как при закрытии формы ее же и уничтожить?

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Как при закрытии формы ее же и уничтожить?

Сообщение tria » 15.08.2006 18:37:51

Это не главная форма приложения.
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10

Сообщение keymaster » 16.08.2006 00:31:51

А разве при Close форма не уничтожается?

Кстати, форма открывается модально или нет?
keymaster
новенький
 
Сообщения: 73
Зарегистрирован: 13.04.2006 12:16:03

Сообщение pda » 16.08.2006 13:42:40

Попробуйте Form.OnClose, Action = caFree.
Аватара пользователя
pda
постоялец
 
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Сообщение volf » 16.08.2006 13:50:51

Код: Выделить всё
procedure TForm2.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  CloseAction := caFree;
end;

Но очень часто после добавления этой строчки возникают Access Violation. Поэтому надо быть осторожным с вызовами уже уничтоженных объектов!
volf
незнакомец
 
Сообщения: 4
Зарегистрирован: 16.08.2006 12:45:45

Сообщение keymaster » 16.08.2006 22:13:06

А можно так:
Код: Выделить всё
  frm_test := Tfrm_test.Create(Application);
  frm_test.ShowModal;
  if frm_test.Free <> nil then frm_test.Free;
keymaster
новенький
 
Сообщения: 73
Зарегистрирован: 13.04.2006 12:16:03

Сообщение tria » 17.08.2006 11:06:57

Извиняюсь за отсутствие. Уточню свой вопрос.
Формы открываются немодально.
Существует, по сути, МДИ приложение. Пользователь может открыть произвольное число форм. Соответственно, в произвольном порядке может закрывать их.

>А разве при Close форма не уничтожается?
При закрытии форма не уничтожается. Надо отдельно сделать Free().

> CloseAction := caFree;
Пробовал. Выдает сообщение об ошибке. Пробовал последней строкой в OnClose() уничтожать саму себя. Тоже сообщение об ошибке.

Пока что реализовал следующим образом. Сделал что-то наподобие панели окон (как в Опере или 1С). При закрытии окна добавляю форму в список форм для уничтожения. При отрисовке панели окон уничтожаю эти формы.
Пока корявовато. Отрисовка происходит необязательно, нельзя быть уверенным, что после закрытия форма уничтожена.

А в чем смысл:
>if frm_test.Free <> nil then frm_test.Free;
По моему, эта строка в корне неверна. Во-первый, Free - это процедура а не функция, во вторых frm_test<>nil - это не гарантия, что форма существует и Free может вызвать ошибку.
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10

Сообщение Sergei I. Gorelkin » 17.08.2006 11:27:22

Вообще говоря, у форм существует метод Release, позволяющий "безопасно" ее уничтожить. "Безопасно" - означает, что запрос на уничтожение ставится в очередь и исполняется после завершения возможного выполнения всех обработчиков событий этой формы.
Однако CloseAction := caFree; приводит к вызову Release сразу же после OnClose.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1405
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение pda » 17.08.2006 14:31:33

tria писал(а):Пробовал. Выдает сообщение об ошибке.

Если MDI форма при caFree выдаёт ошибку, то это уже баг, надо оформлять...

tria писал(а):По моему, эта строка в корне неверна. Во-первый, Free - это процедура а не функция, во вторых frm_test<>nil - это не гарантия, что форма существует и Free может вызвать ошибку.

Строка бессмысленна, т.к. Free специально сделана для безопасного вызова деструктора. Она должна проверять существование объекта. Однако, я слишком часто натыкаюсь, что FPC реализация сделана на живую нитку... :-(
Аватара пользователя
pda
постоялец
 
Сообщения: 303
Зарегистрирован: 27.05.2005 19:59:53

Сообщение Сергей Смирнов » 17.08.2006 14:59:27

tria писал(а):Извиняюсь за отсутствие. Уточню свой вопрос.
Формы открываются немодально.
Существует, по сути, МДИ приложение. Пользователь может открыть произвольное число форм. Соответственно, в произвольном порядке может закрывать их...

Вот эту http://freepascal.ru/article//lazarus/20050523080000/ статью читали? Вроде бы там похожий случай описан.


Atrus писал(а):Если MDI форма при caFree выдаёт ошибку, то это уже баг, надо оформлять...
Вот именно!
Аватара пользователя
Сергей Смирнов
энтузиаст
 
Сообщения: 595
Зарегистрирован: 28.04.2005 13:23:25
Откуда: Москва

Сообщение keymaster » 17.08.2006 15:50:55

А в чем смысл:
>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;
keymaster
новенький
 
Сообщения: 73
Зарегистрирован: 13.04.2006 12:16:03

Сообщение tria » 17.08.2006 17:17:28

>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)
На Делфи у меня это условие не выполнялось и все нормально работало...
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10

Сообщение tria » 17.08.2006 17:26:24

Atrus писал(а): Free специально сделана для безопасного вызова деструктора. Она должна проверять существование объекта. Однако, я слишком часто натыкаюсь, что FPC реализация сделана на живую нитку...

Может я какой-то неправильный, но у меня и в Делфи применение Free к уже уничтоженному объекту ВСЕГДА приводило к ошибке.
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10

Сообщение Сергей Смирнов » 17.08.2006 18:15:02

tria писал(а):В статье предполагается, что работает CloseAction := caFree;, а у меня почему-то после этого возникает ошибка.
Это только у меня одного? У кого-то такой код работает?
И еще из статьи:
"Все объекты приложения должны иметь уникальные имена" - это условие правильности работы любого LCL приложения? (в примере в статье при невыполнении этого условия не будет работать код
(Application.FindComponent(FormName) as TForm).SetFocus)
На Делфи у меня это условие не выполнялось и все нормально работало...
Работать не будет даже создание формы с именем, идентичным имени уже существующей формы. Я точно не уверен, но думаю, что это обязательное условие и для дельфи. Иначе RTTI работать не сможет. Сейчас, кажется, именование создаваемых форм вручную уже не требуется, т.к. LCL научили это делать самостоятельно.

В своё время я бодался с разработчиками по поводу встраивания форм в панель как временной замены MDI. Там были (и, наверное, так и остались) глюки и различия в работе в винде и линухе. Однако, то ли меня не поняли, то ли решили, что я хочу странного. В общем эта тема подвисла, хотя и всплывает с некоторой периодичностью в разных видах. В большинстве случаев исправление такого рода глюков относят на post 1.0.
Аватара пользователя
Сергей Смирнов
энтузиаст
 
Сообщения: 595
Зарегистрирован: 28.04.2005 13:23:25
Откуда: Москва

Сообщение tria » 17.08.2006 19:23:10

В общем, пока нашел следующее:
В простом приложении 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

На формах множество компонент, созданных динамически. Контроля за тем, чтобы имена были разными я не делал. Проект портирован с Делфи, там все работало.
tria
постоялец
 
Сообщения: 401
Зарегистрирован: 03.04.2006 11:24:10

Сообщение volf » 17.08.2006 19:36:40

Для того чтоб не возникало проблем с уничтоженными объектами лучше всего использовать процедуру
Код: Выделить всё
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, но при грамотном подходе ее вполне достаточно.
volf
незнакомец
 
Сообщения: 4
Зарегистрирован: 16.08.2006 12:45:45

След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 29

Рейтинг@Mail.ru