Изучение ООП

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

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

Александр Яшин
новенький
Сообщения: 67
Зарегистрирован: 21.11.2009 08:31:01

Сообщение Александр Яшин »

Получается, что владельцем второй формы надо назначать Form1, а не глобальный объект Application?
Почему можно писать и так:

Код: Выделить всё

Form2:= TForm.Create(Form1);
и так:

Код: Выделить всё

Form2:= TForm1.Create(Form1);
Последний раз редактировалось Александр Яшин 15.04.2010 12:49:07, всего редактировалось 3 раза.
Аватара пользователя
AbakAngelSoft
постоялец
Сообщения: 273
Зарегистрирован: 06.08.2008 19:28:26
Откуда: Краснодар
Контактная информация:

Сообщение AbakAngelSoft »

Александр Яшин писал(а):Почему можно писать и так:

Потому-что у вас Form2 имеет тип TForm т.е. может содержать указатель на объект любого класса-потомка TForm
Если необходимо обезопасить себя нужно указать корректный тип, например

Код: Выделить всё

Form2: TForm2;
Александр Яшин
новенький
Сообщения: 67
Зарегистрирован: 21.11.2009 08:31:01

Сообщение Александр Яшин »

1. Если закрыть вторую форму кнопкой закрытия окна, то форма останется в памяти и будет окончательно уничтожена только после закрытия Form1?
2. Как ее сразу уничтожить при нажатии кнопки закрытия? Т.е. как вставить обработчик OnDestroy, ведь в инспекторе объектов свойств Form2 не видно.
Climber
постоялец
Сообщения: 415
Зарегистрирован: 03.06.2007 20:09:57
Откуда: Москва

Сообщение Climber »

Александр Яшин писал(а):1. Если закрыть вторую форму кнопкой закрытия окна, то форма останется в памяти и будет окончательно уничтожена только после закрытия Form1?
Да.
Александр Яшин писал(а):2. Как ее сразу уничтожить при нажатии кнопки закрытия? Т.е. как вставить обработчик OnDestroy, ведь в инспекторе объектов свойств Form2 не видно.

Точно не уверен, но вроде бы в обработчик OnClose надо вставить вызов то ли Release, то ли чего-то подобного...
Второй вариант - в Form1 сделать процедуру с единственным параметром Sender и написать примерно так:

Код: Выделить всё

procedure TForm1.FormDestroyer(Sender: TObject);
begin
  FreeAndNil(Form2);
end;
// где-нибудь типа обработчика TForm2.OnCreate написать:
OnClose:=@Form1.FormDestroyer;
 
За кошерность советов не ручаюсь, но у меня что-то типа такого работало ;)
Sergei I. Gorelkin писал(а):Это известная фраза, но означает она то, что эти среды навязывают определенный стиль кода, который соотносится и с ООП, и с правильным дизайном довольно-таки опосредованно.
Это многое объясняет!!! Меня давно терзали смутные сомнения, но теперь все встало на свои места. Я пытался изучать тру ООП и соотносить с тем, что я вижу в Delphi и меня не оставляло чувство смутного беспокойства, что либо что-то здесь не так, либо я чего-то не понимаю. Оказалось, что верно первое.
Стоит, однако, заметить, что "навязывают" не значит "запрещают делать иначе". Хотя в большинстве случаев (в том числе моем :oops: ) навязывание прошло успешно.
Аватара пользователя
AbakAngelSoft
постоялец
Сообщения: 273
Зарегистрирован: 06.08.2008 19:28:26
Откуда: Краснодар
Контактная информация:

Сообщение AbakAngelSoft »

Александр Яшин писал(а):Как ее сразу уничтожить при нажатии кнопки закрытия? Т.е. как вставить обработчик OnDestroy, ведь в инспекторе объектов свойств Form2 не видно.


Код: Выделить всё

TForm2 = ...
protected
    procedure DoClose(var CloseAction: TCloseAction); override;
end;

procedure TForm2.DoClose(var CloseAction: TCloseAction);
begin
  inherited DoClose(CloseAction);
  CloseAction := caFree;
end;
Александр Яшин
новенький
Сообщения: 67
Зарегистрирован: 21.11.2009 08:31:01

Сообщение Александр Яшин »

Climber писал(а):// где-нибудь типа обработчика TForm2.OnCreate написать:
OnClose:=@Form1.FormDestroyer;
[/code]


unit1.pas(54,14) Error: Incompatible types: got "<procedure variable type of procedure(TObject) of object;Register>" expected "<procedure variable type of procedure(TObject,var TCloseAction) of object;Register>"
Аватара пользователя
AbakAngelSoft
постоялец
Сообщения: 273
Зарегистрирован: 06.08.2008 19:28:26
Откуда: Краснодар
Контактная информация:

Сообщение AbakAngelSoft »

еще желательно в той форме где хранится ссылка контролировать самоуничтожение дочерней формы наиболее правильно это будет делать так:
при создании формы:

Код: Выделить всё

  Form2 := TForm.Create(Application);
  Form2.FreeNotification(Self);

а самой форме - хозяине:

Код: Выделить всё

TForm1 = ...
protected
  procedure Notification(AComponent: TComponent; Operation: TOperation); override;
end;

procedure TForm1.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) and (AComponent = Form2) then Form2 := nil;
end;


Добавлено спустя 2 минуты 34 секунды:
Да и еще не забываем случай если Form1 будет уничтожена до Form2:

Код: Выделить всё

  TForm1 = ...
  public
    destructor Destroy; override;
  end;

destructor TForm1.Destroy;
begin
  if Assigned(Form2) then Form2.RemoveFreeNotification(Self);
  inherited Destroy;
end;
Александр Яшин
новенький
Сообщения: 67
Зарегистрирован: 21.11.2009 08:31:01

Сообщение Александр Яшин »

AbakAngelSoft писал(а):

Код: Выделить всё

TForm2 = ...
protected
    procedure DoClose(var CloseAction: TCloseAction); override;
end;

procedure TForm2.DoClose(var CloseAction: TCloseAction);
begin
  inherited DoClose(CloseAction);
  CloseAction := caFree;
end;


В примере рассматривается случай динамического создания формы, т.е. без предварительного создания класса формы TForm2.
Аватара пользователя
AbakAngelSoft
постоялец
Сообщения: 273
Зарегистрирован: 06.08.2008 19:28:26
Откуда: Краснодар
Контактная информация:

Сообщение AbakAngelSoft »

Александр Яшин писал(а):без предварительного создания класса формы TForm2.

не кошерно, но собственно ничего не меняеться и в этом случае:

Код: Выделить всё

  Form2 := TForm.Create(Application);
  Form2.FreeNotification(Self);
  Form2.OnClose := @Form2Close;

procedure TForm1.Form2Close(Sender: TObject; var CloseAction: TCloseAction);
begin
  CloseAction := caFree;
end;


Добавлено спустя 56 секунд:
Кстати класс формы можно создать и без дизайнера, а как обычный класс ручками - если загвоздка в этом!
Александр Яшин
новенький
Сообщения: 67
Зарегистрирован: 21.11.2009 08:31:01

Сообщение Александр Яшин »

Нет, не в этом. Мне нужно написать программу в которой пользователь может воспользоваться функцией поиска. Но, может случиться так, что пользователь этой функцией и не воспользуется. В таком случае не хотелось заранее "зря" создавать вторую форму. Поэтому возникла идея создавать эту форму динамически, лишь когда это необходимо.
Предложенный тобой код работает. Спасибо!
Кстати, посмотри весь пример.Вторая форма создается "ручками".
Аватара пользователя
AbakAngelSoft
постоялец
Сообщения: 273
Зарегистрирован: 06.08.2008 19:28:26
Откуда: Краснодар
Контактная информация:

Сообщение AbakAngelSoft »

Я про это и говорил:
класс можно создать руками без дизайнера, тогда форма не будет создаваться при старте программы.
И даже используя дизайнер форму можно выкинуть из списка автосоздаваемых.
"Проект" > "Параметры проекта" > "Формы"
Все что в левом списке будет создано при старте, а то что в правом надо создавать во время выполнения.
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

У меня такой вопрос: Если компоненты создаются по принципу

Код: Выделить всё

NewComponent  := TNewComponent.Create(ParentPanel);
NewComponent.Parent := ParentPanel;
, то при

Код: Выделить всё

FreeAndNil(ParentPanel);
все NewComponent тоже корректно уничтожатся или нужно их вручную уничтожать?
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

VirtUX писал(а):У меня такой вопрос: Если компоненты создаются по принципу

Код: Выделить всё

NewComponent  := TNewComponent.Create(ParentPanel);
NewComponent.Parent := ParentPanel;
, то при

Код: Выделить всё

FreeAndNil(ParentPanel);
все NewComponent тоже корректно уничтожатся или нужно их вручную уничтожать?

y TComponent нет свойства Parent, у них есть свойство Owner.
свойство Parent есть только у TControl-ов

так вот, все компоненты, которым ParentPanel приходиться Owner-ом - будут уничтожены.
но контролы, которым, ParentPanel приходиться Parent-ом НЕ БУДУТ уничтожены, зато их Parent обратится в nil!

грубо говоря так:
Owner-отвечает за "период жизни"
Parent-отвечает за глазуальный порядок (порядок отрисовки, переключения фокуса, видимость, доступность (enabled))
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

скалогрыз писал(а):y TComponent нету свойства Parent, у них есть свойство Owner.
свойство Parent есть только у TControl-ов

Это я образно.
скалогрыз писал(а):так вот, все компоненты, которым ParentPanel приходиться Owner-ом - будут уничтожены.
но контролы, которым, ParentPanel приходиться Owner-ом НЕ БУДУТ уничтожены, зато их Parent обратится в nil!

Жаль. А было б удобно иметь свойство ClearPredDestroy: boolean;, где TRUE - очищать перед деструкцией все TWinControl созданные с Parent равным этому объекту (Self).
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

VirtUX писал(а):Жаль. А было б удобно иметь свойство ClearPredDestroy: boolean;, где TRUE - очищать перед деструкцией все TWinControl созданные с Parent равным этому объекту (Self).

если я не ошибаюсь, то при загрузке компонентов с формы, Owner и Parent у каждого загруженного объекта одинаковые.

однако, что мешает?

Код: Выделить всё

procedure SetChildsOwnerToSelf(AControl: TWinControl);
var
  i : integer;
begin
  if not Assigned(AControl) then Exit;
  for i:=0 to AControl.ContolCount-1 do
    AControl.Controls[i].Owner:=AControl;
end;
Ответить