Модераторы: 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   Вверх
RomanEEP
Дата 10.1.2010, 22:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



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

Процедура объекта ничем не отличается от обыкновенной процедуры  (с тем отличием что у процедуры объекта есть скрытый параметр - указатель на объект располагающийся в регистре EAX). По поэтому из любой процедуры объекта можно беспрепятсвенно удалить объект. Просто нужно понимать, что после удаления указатель на объект недействителен и нельзя обращаться к полям, свойствам и методам объекта. Компилятор "автоматически" к ним НИКОГДА обращаться не будет, поэтому если в твоем коде нет обращений к данным объекта после удаления - все отлично работает.
В большинстве событий объектов после вызова обработчика идет обращения к каким либо данным объекта, поэтому вызывать Free или Destroy внутри обработчика событий и не рекомендуется. Хотя вполне возможно.

Цитата(shmelina @  10.1.2010,  19:36 Найти цитируемый пост)
Так тоже не хорошо. Форма в принципе не должна ничего знать о TModul. Это плохой стиль программирования.

Если форма не будет знать про TModul она В ПРИНЦИПЕ не сможет его удалить. Чудес не бывает. Нельзя удалить не зная что. Точнее можно, но результат будет непредсказуемый, это "плохой стиль програмирования")))

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


Шустрый
*


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

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



А корректно ли будет у объекта TModul сделать обработчик события закрытия формы и выполнить Free?
Код

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

procedure TModul.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Free;
end;

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


Опытный
**


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

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



Нет. Будет такая цепочка вызовов:
TForm.DoClose->TModul.FormClose->TModul.Destroy->TForm.Destroy
после выполнения TForm.Destroy при возврате в TForm.DoClose результат один - AV 
PM MAIL   Вверх
shmelina
Дата 10.1.2010, 22:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(RomanEEP @  10.1.2010,  22:45 Найти цитируемый пост)
Нет. Будет такая цепочка вызовов:
TForm.DoClose->TModul.FormClose->TModul.Destroy->TForm.Destroy

Скорее так:
TForm.DoClose->TModul.FormClose->TForm.Destroy->TModul.Destroy
Но это наверно не меняет смысла.
PM MAIL   Вверх
RomanEEP
Дата 10.1.2010, 23:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



если точнее, то:
TForm.DoClose->TModul.FormClose->TModul.Free->TModul.Destroy->TForm.Free->TForm.Destroy
хотя в нашем случае разницы нет
PM MAIL   Вверх
shmelina
Дата 10.1.2010, 23:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Т.е. ты предлагаешь в деструкторе формы удалять объект?
Тогда наверно можно так?
Код

procedure TModul.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

procedure TModul.FormDestroy(Sender: TObject);
begin
  Form := nil;
  Free;
end;

destructor TModul.Destroy;
begin
  if Assigned(Form) then
    Form.Free;
  inherited;
end;


Это сообщение отредактировал(а) shmelina - 10.1.2010, 23:22
PM MAIL   Вверх
bems
Дата 11.1.2010, 04:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

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



Код

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

implementation

{ TModul }

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

end.


Это сообщение отредактировал(а) bems - 11.1.2010, 04:34


--------------------
Обижено школьников: 8
PM MAIL   Вверх
shmelina
Дата 11.1.2010, 09:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



bems, спасибо за идею. Совсем забыл про это. Если по другому не получится - вернуть к ней.

То, что я написал в предыдущем посте, корректно?

Теперь нужно в контейнере удалить этот объект. В общем у меня получилось так (тестовый проект):
Код

unit MainFo;

interface

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

type
  TMainForm = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    ModulList: TModulList;
  end;

var
  MainForm: TMainForm;

implementation

uses Modl;

{$R *.dfm}

procedure TMainForm.Button1Click(Sender: TObject);
begin
  ModulList.ShowModul(mtOne);
end;

procedure TMainForm.Button2Click(Sender: TObject);
begin
  ModulList.ShowModul(mtTwo);
end;

procedure TMainForm.Button3Click(Sender: TObject);
begin
  ModulList.ShowModul(mtThree);
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  ModulList := TModulList.Create(Self);
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  ModulList.Free;
end;

end.

Код

unit ModlList;

interface

uses Modl,
  Generics.Collections, Classes;

type
  TModulList = class(TObjectList<TModul>)
  private
    Owner: TComponent;
    procedure ModulFormDestroy(AModul: TModul);
  public
    constructor Create(AOwner: TComponent);
    function ShowModul(AModulType: TModulType): TModul;
  end;

implementation

{ TModulList }

constructor TModulList.Create(AOwner: TComponent);
begin
  inherited Create;
  Owner := AOwner;
end;

procedure TModulList.ModulFormDestroy(AModul: TModul);
var
  I: Integer;
begin // Удаляем модуль - его форма только что умерла
  for I := Count - 1 downto 0 do 
    if Items[I] = AModul then
      Delete(I);
end;

function TModulList.ShowModul(AModulType: TModulType): TModul;
var
  I: Integer;
begin
  Result := nil;
  // Ищем модуль. Он может быть уже создан.
  for I := 0 to Count - 1 do
    if Items[I].ModulType = AModulType then
    begin
      Result := Items[I];
      Result.Show;
      Break;
    end;
  // Модуль не создан. Создаем.
  if not Assigned(Result) then
  begin
    Result := TModul.Create(Owner, AModulType);
    Result.OnFormDestroy := ModulFormDestroy;
    Add(Result);
  end;
end;

end.

Код

unit Modl;

interface

uses
  Forms, Classes, SysUtils;

type
  TModul = class;

  TModulType = (mtOne, mtTwo, mtThree);
  TNotifyModul = procedure(AModul: TModul) of object;

  TModul = class
  private
    Form: TForm;
    FModulType: TModulType;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormDestroy(Sender: TObject);
  public
    OnFormDestroy: TNotifyModul;
    constructor Create(AOwner: TComponent; AModulType: TModulType);
    destructor Destroy; override;
    property ModulType: TModulType read FModulType;
    procedure Show;
  end;

implementation

{ TModul }

constructor TModul.Create(AOwner: TComponent; AModulType: TModulType);
begin
  inherited Create;
  FModulType := AModulType;
  Form := TForm.Create(AOwner);
  Form.Caption := IntToStr(Ord(AModulType) + 1);
  Form.OnClose := FormClose;
  Form.OnDestroy := FormDestroy;
  Form.Show;
end;

destructor TModul.Destroy;
begin
  // Формы может уже не быть, если ее закрыл сам пользователь.
  if Assigned(Form) then
    Form.Free;
  inherited;
end;

procedure TModul.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

procedure TModul.FormDestroy(Sender: TObject);
begin
  Form := nil;
  OnFormDestroy(Self);
end;

procedure TModul.Show;
begin
  Form.Show;
end;

end.


Исходники прилагаю (delphi 2009). Посмотрите, пожалуйста. FastMM теперь молчит как партизан.

Это сообщение отредактировал(а) shmelina - 11.1.2010, 09:38

Присоединённый файл ( Кол-во скачиваний: 3 )
Присоединённый файл  FreeSelf.zip 2,44 Kb
PM MAIL   Вверх
shmelina
Дата 12.1.2010, 16:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Никто не ответил - ну и ладно. Главное помогли и все работает. Спасибо за помощь!
Наберу 100 сообщений - все поставлю плюсы smile.
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

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

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

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

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


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

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


 




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


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

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