user1137313
user1137313

Reputation: 2410

Delphi destroy dynamic control onDestroy of the parent form

How do I make sure a dynamic control is destroyed along with it's parent form?

So, from the main form, I create a button for a secondary form, then I display the secondary form with the button on it.

Now, I want to make sure the created button is destroyed together with the secondary form.

Would it be enough to make the Parent of the Button, the secondary form? Would that do it?

I am using a custom descendant of the TButton Class - TMyButton. So in my constructor I have the next code:

constructor TMyButton.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);
   Self.OnClick := Self.MyButtonClick;
   Self.Parent:=TWinControl(AOwner);
   self.Visible := true;
end;

Is this going to be ok? It works for me, it throws no errors, but I want to make sure that the said button is destroyed together with the form on which it is placed.

The MyButton will be placed on a secondary form, let's say 'Form2' So there will be a code like:

var
  bt:TMyButton;
begin
      bt:=TMyButton.Create(Form2);
      bt.Parent:=Form2;
      ...
      form2.Show;
end;

Upvotes: 1

Views: 1806

Answers (3)

Disillusioned
Disillusioned

Reputation: 14842

The short answer is: Yes, your button will be destroyed along with the form.
But it would be useful if you know how to verify this for yourself.

Write the following code: (NOTE: Don't forget override where you declare the method.)

destructor TMyButton.Destroy;
begin
  inherited Destroy;
end;

Now put a breakpoint on the line inherited Destroy;. Run your application in the debugger, and ensure the code stops at the breakpoint. I.e.

  • Open your child form.
  • Destroy your child form. (Emphasis on Destroy, because if CloseAction is caHide, simply closing your form won't be sufficient for the test.)
  • Verify that you reach the breakpoint.
  • Press F9 to continue running.
  • Also verify that you reach the breakpoint only once per button. (Otherwise there would be a double-destroy bug that could lead to access violations and unpredictable behaviour.)

You can also enable Debug DCU's in your compiler options. Then when you hit the breakpoint examine the call stack Ctrl+Alt+S to see where in VCL code your button is being destroyed from.

Upvotes: 1

NGLN
NGLN

Reputation: 43669

First of all: setting a control's parent in its constructor is wrong! For a control created in design time, the IDE is and will be responsible for setting a parent. For a control created in runtime, the creating code should be responsible for setting a parent.

How do I make sure a dynamic control is destroyed along with it's parent form?

A control which has a Parent will automatically be destroyed when that immediate Parent is destroyed. Furthermore, a control which has an Owner will automatically be destroyed when that Owner is destroyed. It the Owner is in the Parent chain of the control then everything is fine. If the Owner is not in the Parent chain of the control, then you have a design problem which could result in unwanted destruction.

Your current constructor is completely unnecessary. Casting the Owner (which could be nil!) to a TWinControl without checks is wrong. But as said, setting the Parent should not be there. Visible is true by default, and assigning the OnClick event will prevent it for further use. Instead, override Click.

Regarding your comment, the calling code would become:

procedure TForm1.Button1Click(Sender: TObject);
var
  Button: TButton;
begin
  Button := TButton.Create(Form2);
  Button.OnClick := Form2.ButtonClick;
  Button.SetBounds(10, 10, 75, 25);
  Button.Parent := Form2;
end;

But this leaves you with no reference to the button. Instead add the variable to a higher scope.

Upvotes: 5

Marcelo Cuadrado
Marcelo Cuadrado

Reputation: 82

With this code you should not have problems.

You're making both the Owner and the Parent is the child form. So when released form. This frees the objects it contains.

I will explain the difference between Parent and Owner: When assigning the Parent, you are indicating "visual container". Is the object that show ... a Form a Panel, a Frame.

Moreover, the Owner is the owner. The Object owner is responsibility to release all objects "slaves".

Normally both the Parent and the Owner is the same, because we design interfaces automatically and put the components visually. When you want to create visual components at runtime must be controlled well who is the Parent, and whom the Owner.

Different is if your in the Owner will set Nil:

Obj := TObject.Create(nil);

There if you have to indicate when you should release it. It's your responsibility.


EDIT: You can use the TButton. Something like this:

procedure TForm1.CreateButton;
var obj: TButton;
begin
  obj := TButton.Create(Form2);
  obj.Parent := Form2;
  Obj.OnClick := MyEventOnClick;
end;

EDIT 2:

Zarko Gajic, in About.com has an excellent article is worth reading.

This can help supplement what you have offered. You can view the article in http://delphi.about.com/od/objectpascalide/a/owner_parent.htm

Upvotes: 1

Related Questions