[Solved] How can I free() the real children?

BlitzMax Forums/BlitzMax Beginners Area/[Solved] How can I free() the real children?

MOBii(Posted 2015) [#1]
Local ii:wxWindow[] = MOBii_Panel[q].Panel.getChildren()
If ii Then
	For Local i:wxWindow = EachIn ii
		If i.getID() Then i.Free()
	Next
End If
How can I free() the real children?


Henri(Posted 2015) [#2]
Hi,

are you trying to free a wxWidget window ? Do you want to free parent and it's children or just the children ?

-Henri


MOBii(Posted 2015) [#3]
MOBii_Panel[q].Panel = New wxScrolledWindow.Create(wxWindow(po), b, _x, _y, _w, _h, wxHSCROLL|wxVSCROLL|$00080000)
panel is a wxScrolledWindow

Example of children: wxListBox, wxSlider, wxButton, wxCheckBox, wxStaticText

my test show me that when I i.Free() I only Free() the local i copy
Local ii:wxWindow[] = MOBii_Panel[q].Panel.getChildren()
If ii Then
	For Local i:wxWindow = EachIn ii
		If i.getID() Then i.Free()
		echo "This is the real child: " + MOBii_Button[0].getID()		' and it print out the id, so it mean the real object is still alive!
	Next
End If

if I don't know: MOBii_Button[0].Free() how can I free the original object?

I know: MOBii_Panel[q].Panel.getChildren()


Henri(Posted 2015) [#4]
From wxWiki: Avoiding Memory Leaks

The wxWidgets-specific part

If we're talking about a class that is derived off wxWindow, there are some special issues: a wxWindow may get events, and if there's an event that should go to an object that has since been deleted, that may make your program crash. This is why a wxWindow (or wxWindow-derived class) should be deleted with care, first making sure there are no pending events bound for that object.

This is done with the Destroy()-method of wxWindow. Instead of using delete, you must use myWindow->Destroy(), which will wait until next idle loop and then do something like delete myWindow;.

For the same reason, you may never create a wxWindow-derived class on the stack (!), since that will be deleted automatically without using Destroy(). Thus for wxWindow-derived classes, you must always use new and ->Destroy(). There is however one exception to this, see #Modal windows below.
Child windows

When a wxWindow is destroyed, it automatically deletes all its children. These children are all the objects that received the window as the parent-argument in their constructors.

As a consequence, if you're creating a derived class that contains child windows, you should use a pointer to the child windows instead of the objects themself as members of the main window.

That is, do

class myNotebook: public wxNotebook
{
private:
wxPanel * panel1;
wxPanel * panel2;
}

instead of

class myNotebook: public wxNotebook
{
private:
wxPanel panel1;
wxPanel panel2;
}

The second format would cause double-deletion problems.
"Managed" windows

For "managed" windows, like frames and dialogs, it is usually better to call ->Close() instead of ->Destroy(). This will generate an EVT_CLOSE before destroying the object. If for some reason you want to delete a control yourself, you would use ->Destroy(), since controls are non-managed windows and do not respond to the EVT_CLOSE;.

Note: When calling ->Close(), memory is not actually freed, but the dialog is just hidden from the user. If you really want to free the memory, you will need to call ->Destroy(). If the dialog has been given a parent frame, you may just call ->Close() as the dialog will be destroyed and freed when the parent frame is.


According to this you should use Destroy() for freeing control from memory also. This should free every child as well, and there might be a slight delay also before every event is processed in order to free properly.


Just for fun here is my function to go through every child control for any given parent. I use it to clear a form:
'Clear all child controls
Function ClearFields(parent:Object)

	Local win:wxWindow = wxWindow(parent)
	If Not win Then Return
	
	Local kids:wxWindow[] = win.GetChildren()
	For Local kid:wxWindow = EachIn kids
	
		If kid.GetChildren() Then ClearFields(kid)
		
		'Type Casting is used to distinguish different controls for control spesific actions
		Local tmpField:wxTextCtrl = wxTextCtrl(kid)
		If tmpField Then
			tmpField.SetValue("")
		EndIf
		
		Local tmpCombo:wxComboBox = wxComboBox(kid)
		If tmpCombo Then
			'tmpCombo.SelectItem(0)
			tmpCombo.Clear()
			tmpCombo.SetValue("")
		EndIf
		
		Local tmpChoice:wxChoice = wxChoice(kid)
		If tmpChoice Then
			tmpChoice.SelectItem(0)
		EndIf
	Next
EndFunction


-Henri


MOBii(Posted 2015) [#5]
WOW I made it, thanks again Henri

I kill the panel:
If Panel.wxObjectPtr	Then	Panel.hide();	KilltheChildren(Panel); Panel.Free()	' I can still only: Panel.Free() not Panel.Destroy(), Maybe that is the reason I can't kid.Destroy() the panel in the KilltheChildren
Modified Henri code
' -----------------------------------------------------------------------[KilltheChildren]---
Method KilltheChildren(_father:Object)
	Local win:wxWindow = wxWindow(_father)
	If Not _father Then Return

	Local kids:wxWindow[] = win.getChildren()
	If kids Then
		For Local kid:wxWindow = EachIn kids
			If kid.wxObjectPtr Then
				If kid.getChildren() Then KilltheChildren(kid)
				If kid.wxObjectPtr Then
					kid.hide()
					Local _k:wxScrolledWindow = wxScrolledWindow(kid)
					If Not _k Then DebugLog "NOT a panel :: kill subkid: " + kid.getID(); kid.Destroy()
				End If
			End If
		Next
	End If
End Method
if I don't kill the sub panels in the KilltheChildren() I don't get the EXCEPTION_ACCESS_VIOLATION crash and the script leak less memory now ^^/


Footnote:
I make a memory test to draw 100 wxStaticText and the editor start crying
I almost start crying to until I realize that drawing 100 wxStaticText make the application really slow!