Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как объекту удалить самого себя? При закрытии формы удалить ее объект 
V
    Опции темы
shmelina
Дата 9.1.2010, 00:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 5.6.2009

Репутация: нет
Всего: нет



Добрый вечер. 

Для лучшего понимания проблемы упрощаю ситуацию.

Есть некий класс. При создании объекта этого класса создается форма.
Нужно, чтобы, при закрытии пользователем этой формы удалялся и класс.

Что-то у меня не получается просто решить эту задачу. Все какие-то сборщики мусора в голову лезут.
Подскажите правильное решение.

Вот код класса:
Код

unit Modl;

interface

uses Forms, Classes;

type
  TModul = class
  private
    Form: TForm;
  public
    constructor Create(AOwner: TComponent);
    destructor Destroy; override;
  end;

implementation

{ TModul }

constructor TModul.Create(AOwner: TComponent);
begin
  inherited Create;
  Form := TForm.Create(AOwner);
  Form.Show;
end;

destructor TModul.Destroy;
begin
  Form.Free;
  inherited;
end;

end.


Нужно, чтобы при закрытии пользователем формы (Form), удалилась (.Free) и форма (Form) и класс (Modul).
PM MAIL   Вверх
RomanEEP
Дата 9.1.2010, 23:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 424
Регистрация: 18.5.2006
Где: Коломна

Репутация: 5
Всего: 8



1 метод: TModul = class(TForm) - если это конечно возможно
2 метод: TModul = class(TInterfacedObject)
PM MAIL   Вверх
Демо
Дата 9.1.2010, 23:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 30
Всего: 50



Цитата(shmelina @  9.1.2010,  00:47 Найти цитируемый пост)
Нужно, чтобы при закрытии пользователем формы (Form), удалилась (.Free) и форма (Form) и класс (Modul).


Т.е. ты хочешь это проделать, не взаимодействуя с другими объектами?

Можешь создавать отдельный поток для вызова Free своего класса. Но согласись, что это изврат и не нужная возможность.
Всего лишь для создания формы плодить свой класс вроде как не имеет смысла - форма и так умеет самоуничтожаться.

Смотри как это делается в реализации TFOrm(TCustomForm), TThread,


--------------------
    
PM MAIL ICQ Skype   Вверх
shmelina
Дата 10.1.2010, 00:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 5.6.2009

Репутация: нет
Всего: нет



Цитата
1 метод: TModul = class(TForm) - если это конечно возможно

Не хотелось бы. TModul - это базовый класс. От него наследуются разные потомки. И придется для каждого такого потомка создавать форму, т. к. компилятор будет требовать {$R *.dfm}. Кривовато это.

Цитата
2 метод: TModul = class(TInterfacedObject)

С этим не знаком еще.

Цитата
Т.е. ты хочешь это проделать, не взаимодействуя с другими объектами?

Можно и взаимодействовать. Я не против. Лишь бы реализация правильная была с точки зрения ООП.
Например, всеми этими TModul управляет контейнер:
Код

unit ModlList;

interface

uses Modl,
  Generics.Collections;

type
  TModulList = class(TObjectList<TModul>)
  end;

implementation

end.


Цитата
Можешь создавать отдельный поток для вызова Free своего класса. Но согласись, что это изврат и не нужная возможность.

Согласен. Вот и обращаюсь за помощью. У меня пока есть идея примерно такая:
- скрывать форму
- ставить флаг, что объект должен быть уничтожен
- и при любом следующем обращении к контейнеру (создан/удален TModul) грохать объект.
Т.е. объект будет уничтожаться какбы с задержкой.

Сложно как-то :(.

Цитата
Всего лишь для создания формы плодить свой класс вроде как не имеет смысла - форма и так умеет самоуничтожаться.

Согласен, но с формой тоже по-дурацки выходит.
PM MAIL   Вверх
Демо
Дата 10.1.2010, 00:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 30
Всего: 50



Цитата(shmelina @  10.1.2010,  00:15 Найти цитируемый пост)
Например, всеми этими TModul управляет контейнер:


Ну так если есть владелец - пусть он и отвечает за уничтожение дочерних объектов - так большинство классов реализовано в Delphi.

Твой контейнер пусть создаст невидимое окно, которое будет сообщения принимать, все дочерние объекты будут посылать сообщения окну, а контейнер обрабатывать.


--------------------
    
PM MAIL ICQ Skype   Вверх
shmelina
Дата 10.1.2010, 02:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 5.6.2009

Репутация: нет
Всего: нет



Цитата
Ну так если есть владелец - пусть он и отвечает за уничтожение дочерних объектов - так большинство классов реализовано в Delphi.

Тут ситуация немного другая. Если бы у меня TModul = class(TForm), то проблем бы не было.
А у меня TModul создает TForm.
Т.е. я создаю объект1, а он создает объект2.
При событии в объект2 (форма закрывается крестиком) нужно удалить и объект1 и объект2.
PM MAIL   Вверх
Демо
Дата 10.1.2010, 07:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 30
Всего: 50



Цитата(shmelina @  10.1.2010,  02:12 Найти цитируемый пост)
Тут ситуация немного другая.


Ты ж выше написал сам про TModulList, который владельцем является.


Цитата(shmelina @  10.1.2010,  02:12 Найти цитируемый пост)
.е. я создаю объект1, а он создает объект2.


и 

Цитата(shmelina @  10.1.2010,  02:12 Найти цитируемый пост)
При событии в объект2 (форма закрывается крестиком) нужно удалить и объект1 и объект2.


Зачем плодить 2 объекта вместо одного?


--------------------
    
PM MAIL ICQ Skype   Вверх
RomanEEP
Дата 10.1.2010, 11:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 424
Регистрация: 18.5.2006
Где: Коломна

Репутация: 5
Всего: 8



метод3:
Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TModul = class;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    FModul: TModul;
  protected
    procedure DoClose(var Action: TCloseAction); override;
  public
    destructor Destroy; override;
  end;

  TModul = class
  private
    FForm: TForm1;
  public
    procedure FormFreed;
    constructor Create(AOwner: TComponent);
    destructor Destroy; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TModul }

constructor TModul.Create(AOwner: TComponent);
begin
  inherited Create;
  FForm := TForm1.Create(AOwner);
  FForm.FModul := Self;
  FForm.Show;
end;

destructor TModul.Destroy;
begin
  FForm.Free;
  inherited;
end;

procedure TModul.FormFreed;
begin
  FForm := nil;
  Free;
end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  FModul := TModul.Create(Application);
end;

destructor TForm1.Destroy;
begin
  if Assigned(FModul) then
    FModul.FormFreed;
  inherited;
end;

procedure TForm1.DoClose(var Action: TCloseAction);
begin
  inherited;
  Action := caFree;
end;

end.

PM MAIL   Вверх
Демо
Дата 10.1.2010, 12:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 30
Всего: 50



Для уничтожения любых объектов можно предложить простейший класс:

Код

unit uOC;

interface

uses
  Windows, Messages,  Classes;

const
  UM_BASE=WM_USER+1;
  UM_FreeObject=UM_BASE+1;
  UM_RegisterObject=UM_BASE+2;
  UM_UnRegisterObject=UM_BASE+3;

type

  TOwnerClass=class
  private
    FList: TList;
    FWnd: THandle;
    FFreeObjectsOnDestroy: Boolean;
    procedure WndProc(var M: TMessage);
  public
    constructor Create(FreeObjectsOnDestroy: Boolean=True);
    destructor Destroy; override;
    procedure RegisterObject(p: Pointer);
    procedure UnRegisterObject(p: Pointer);
    procedure FreeObject(p: Pointer);
  end;

implementation

{ TOwnerClass }

constructor TOwnerClass.Create(FreeObjectsOnDestroy: Boolean=True);
begin
  FList := TList.Create;
  FWnd := AllocateHWND(WndProc);
  FFreeObjectsOnDestroy := FreeObjectsOnDestroy;
end;

destructor TOwnerClass.Destroy;
begin
  DeallocateHWND(FWnd);
  if FFreeObjectsOnDestroy then
  begin
    while FList.Count>0 do
    begin
      TObject(FList[0]).Free;
      FList.Delete(0);
    end;
  end;
  FList.Free;
end;

procedure TOwnerClass.FreeObject(p: Pointer);
begin
  if p<>nil then PostMessage(FWnd,UM_FreeObject,Integer(p),0);
end;

procedure TOwnerClass.RegisterObject(p: Pointer);
begin
  if p<>nil then PostMessage(FWnd,UM_RegisterObject,Integer(p),0);
end;

procedure TOwnerClass.UnRegisterObject(p: Pointer);
begin
  if p<>nil then PostMessage(FWnd,UM_UnRegisterObject,Integer(p),0);
end;

procedure TOwnerClass.WndProc(var M: TMessage);
var
  i: Integer;
begin
  case M.Msg of
    UM_FreeObject,UM_UnRegisterObject:
      begin
        for i := FList.Count-1 downto 0 do
        begin
          if Pointer(M.WParam)=FList[i] then
          begin
            if M.Msg=UM_FreeObject
              then TObject(FList[i]).Free;
            FList.Delete(i);
          end;
        end;
      end;
    UM_RegisterObject: FList.Add(Pointer(M.WParam));
  else DefWIndowProc(FWnd,M.Msg,M.WParam,M.LParam);
  end;

end;

end.



Пример использования:

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, uOC;

type

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TMyClass1=class
  private
    FOwnerClass: TOwnerClass;
  public
    constructor Create(OwnerClass: TOwnerClass);
    procedure Process;
    procedure FreeSelf;
  end;

var
  Form1: TForm1;
  OC: TOwnerClass;
  MyObject: TMyClass1;
implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not Assigned(OC) then OC := TOwnerClass.Create;
  TMyClass1.Create(OC);
end;

{ TMyClass1 }

constructor TMyClass1.Create(OwnerClass: TOwnerClass);
begin
  FOwnerClass := OwnerClass;
  FOwnerClass.RegisterObject(Self);
  Process;
end;

procedure TMyClass1.FreeSelf;
begin
  FOwnerClass.FreeObject(Self);
end;

procedure TMyClass1.Process;
var
  i: Integer;
begin
  for i := 0 to 10 do Sleep(10);
  FreeSelf;
end;

end.




--------------------
    
PM MAIL ICQ Skype   Вверх
shmelina
Дата 10.1.2010, 13:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 5.6.2009

Репутация: нет
Всего: нет



Цитата
Зачем плодить 2 объекта вместо одного? 

Мне не нужно, чтобы TModul был наследником TForm.

RomanEEP, вы в методе объекта предлагаете уничтожить сам объект. Это не хорошо.
Код

procedure TModul.FormFreed;
begin
  FForm := nil;
  Free;
end;

Еще не хорошо, что модуль знает о форме, а форма о модуле. 
Не нравится что и форма и модуль отдельно объявлены. И наследовать потом сложно будет. И в каждом юните  наследника форму пустую таскать. В общем не то это. 

Должен быть модуль и он должен создавать форму. Программа пишется так, что форм в ней вообще нет. Все создается динамически. Весь GUI-интерфейс описан в БД.

Демо, вам отвечу позже - убегаю. Но хотелось бы обойтись без сообщений.
PM MAIL   Вверх
RomanEEP
Дата 10.1.2010, 17:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 424
Регистрация: 18.5.2006
Где: Коломна

Репутация: 5
Всего: 8



Цитата(shmelina @  10.1.2010,  13:55 Найти цитируемый пост)
RomanEEP, вы в методе объекта предлагаете уничтожить сам объект. Это не хорошо.

не надо путать метод с обработчиком события. Вызвать удаления объекта в последней строчке метода, вызываемого ИЗВНЕ безопасно на 100%

Цитата(shmelina @  10.1.2010,  13:55 Найти цитируемый пост)
Еще не хорошо, что модуль знает о форме, а форма о модуле. 

Так ведь никто не мешает объявить
Код

FForm: TObject;
FModul: TObject;

и все успешно друг о друге забудут)) навсегда)))

Асинхронный вызов который предложил Демо - хороший способ, но FModul будет удален не скоро после закрытия формы, т.е какое-то время программа будет в состояни когда модуль еще есть, а форма уже тютю и в отладке сообщения не айс конечно
PM MAIL   Вверх
shmelina
Дата 10.1.2010, 19:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 5.6.2009

Репутация: нет
Всего: нет



Цитата(RomanEEP @  10.1.2010,  17:20 Найти цитируемый пост)
не надо путать метод с обработчиком события.

А какая разница? Обработчик - это частный случай метода.
Цитата(RomanEEP @  10.1.2010,  17:20 Найти цитируемый пост)
Вызвать удаления объекта в последней строчке метода, вызываемого ИЗВНЕ безопасно на 100%

Не уверен, что это безопасно.
Ты вызываешь Free, управление программой переходит в метод Free, там объект уничтожается, затем идет возврат из процедуры Free в метод FormFreed, которого уже нет, т. к. объект освобожден.
Цитата(RomanEEP @  10.1.2010,  17:20 Найти цитируемый пост)
Так ведь никто не мешает объявить
FForm: TObject;
FModul: TObject;
и все успешно друг о друге забудут)) навсегда)))

Так тоже не хорошо. Форма в принципе не должна ничего знать о TModul. Это плохой стиль программирования. 
Цитата(RomanEEP @  10.1.2010,  17:20 Найти цитируемый пост)
Асинхронный вызов который предложил Демо - хороший способ, но FModul будет удален не скоро после закрытия формы, т.е какое-то время программа будет в состояни когда модуль еще есть, а форма уже тютю и в отладке сообщения не айс конечно 

Там как-то сложно все. Да еще и с сообщениями. Да еще и форма от модуля отделена. В юните не должно быть объявленных форм.
PM MAIL   Вверх
shmelina
Дата 10.1.2010, 20:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 5.6.2009

Репутация: нет
Всего: нет



Я кажется понял что мне нужно.
У формы есть событие OnClose. 
В нем есть параметр var Action: TCloseAction. 
Если присвоить ему Action := caFree, то форма уничтожится сама!
Как это происходит: В TCustomForm.Close вызывается Release.
Сам Release выглядит так: PostMessage(Handle, CM_RELEASE, 0, 0);
Форма обрабатывает это сообщение так: Free.

Т.е. с помощью PostMessage сообщение ставится в очередь (сразу не вызывается!) и обрабатывается так:
Код

procedure CMRelease(var Message: TMessage); message CM_RELEASE;
...
procedure TCustomForm.CMRelease;
begin
  Free;
end;


У меня два вопроса:
1. Действительно безопасно уничтожать самого себя через сообщение?
2. Как нечто подобное сделать в моем случае (применительно в TModul)?

Слабовато у меня с сообщениями.

Это сообщение отредактировал(а) shmelina - 10.1.2010, 20:49
PM MAIL   Вверх
Демо
Дата 10.1.2010, 20:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 30
Всего: 50



Цитата(shmelina @  10.1.2010,  20:48 Найти цитируемый пост)
У формы есть событие OnClose. В нем есть параметр var Action: TCloseAction. Если присвоить ему Action := caFree, то форма уничтожится сама!


Тебе про это, по-существу, с первых сообщений намекали.


Цитата(shmelina @  10.1.2010,  20:48 Найти цитируемый пост)
1. Действительно безопасно уничтожать самого себя через сообщение?


Да.


Цитата(shmelina @  10.1.2010,  20:48 Найти цитируемый пост)
2. Как нечто подобное сделать в моем случае (применительно в TModul)?

Я ж тебе привёл пример именно такого класса.
Регистрируешь в нём ЛЮБОЙ свой объект, а уничтожаешь именно через него.


--------------------
    
PM MAIL ICQ Skype   Вверх
shmelina
Дата 10.1.2010, 21:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 66
Регистрация: 5.6.2009

Репутация: нет
Всего: нет



Т.е. прикинуться окном?
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1219 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.