EmbedWithin and "Unembed"

Know I can use EmbedWithin to add a container to a page.

How do I remove one?

[quote=236143:@Jay Menna]Know I can use EmbedWithin to add a container to a page.

How do I remove one?[/quote]

Use a window or module property to retain a reference to the container you embed, then use Close on it when you want to remove it.

[code]tc = New TestContainer // tc is a ContainerControl window property

tc.EmbedWithin(Self, 10, 100, 300,400)[/code]

Remove :

tc.close

[quote=236144:@Michel Bujardet]
Remove :

tc.close

I recognized a strange behavior after closing an embedded webcontainer. It seems as if the control is not Nil after closing it. Will this produce a memory leak?

To see this in action, place a property ct as webcontainer on your page. Also ctMsg should have been created as a webcontainer in your project. Then place a WebButton on your page with the following code in the action-event:

[code]Sub Action()
Select case me.Caption
Case “Open”
ct = new ctMsg
ct.EmbedWithin(self, 0, self.height - ct.Height, self.width, ct.Height)
me.Caption = “Close”

Case “Close”
'Place a breakpoint here
if ct <> Nil then
ct.close
end if
’ To reopen the webcontainer it should be:
’ me.Caption = “Open”
’ But for testing purposes I commented it

Case else
'Shouldn’t happen
MsgBox “Ooops - Error!”

end select
End Sub[/code]

If the button has the caption “Open”, the webcontainer will be embedded dynamically. If the button has the caption “Close”, the webcontainer will be closed. But if you click again on the button after it is closed (it still has the caption “Close”, see the comment in the code), you will see that ct is not Nil. What does that mean?

The control won’t be destroyed until you remove the reference to it. ct.Close does not set ct equal to Nil; you must do that yourself if you want to destroy the container completely. It will only be destroyed after all references are released. You need to do this instead:

Case "Close"
'Place a breakpoint here
   if ct <> Nil then
      ct.close
      ct = Nil 
   end if

Thanks @Ed, this works.

But I don’t really understand why a close is not sufficient. Especially because I can’t reference to the webcontainer, if I close it but don’t set it to Nil:

[code]Sub Action()
Select case me.Caption
Case “Open”
if ct = Nil then
ct = new ctMsg
end if
// THIS CRASHES after closing ct (see “Close”) >> NilObjectExpression
ct.EmbedWithin(self, 0, self.height - ct.Height, self.width, ct.Height)
me.Caption = “Close”

Case “Close”
if ct <> Nil then
ct.close
//ct = Nil
end if
me.caption = “Open”

Case else
MsgBox “Ooops - Error!”

end select
End Sub[/code]

My concern is that if you don’t work very carefully with embedde webcontainers your code might very easily leak memory. And this could simply be done from the XOJO-framework when closing the embedded webcontainer. Or do I miss something?

I don’t have enough experience with container controls to be able to address those specifically. Perhaps someone else can. But with a full window, it is possible to Open the window, run something, Close it, then Open it again.

And, in general, any object in Xojo will exist until all the references to it are gone, either by setting the object variable to Nil or assigning another object to the variable. So, not only containers, but anything else that is an object behaves this way.

You really are not leaking memory since there is still a reference to the object in your program. Let’s look at another approach:

Case "Open"
  ct = New ctMsg
  If ct <> Nil Then
    ct.EmbedWithin(self, 0, self.height - ct.Height, self.width, ct.Height)
    me.Caption = "Close"
  Else
    // Some error handling based on not being able to create a new ctMsg.
  End If

When you set ct to the new instance of ctMsg you create, the old one loses its reference within your program. If that’s the only reference, the old ctMsg is destroyed. You should be able to see this by creating a method in your ctMsg container called “Destructor” and putting a Break statement in it. The Break will trigger after the ct = New ctMsg line runs for the second time. That’s the first object running its Destructor after it is replaced by the second. Since the first is being destroyed at that point, you have not leaked a ctMsg object.

Hope this helps.

Thanks Ed, for the detailed information. Now I understand. I learned a lot today :slight_smile:

Glad I could help.

I always will set an object variable explicitly to Nil if I know I’m done with it. I’ve had what I call “zombie” objects suddenly come to life and do things I don’t intend. It’s also somewhat self-documenting code.

Close destroys the controls within the container, but you can still access the properties of the container, which can be beneficial at times.