Ownership and Lifetime
MQL5 does not have automatic garbage collection.
ModernUI keeps the model simple:
Root owns the root UI tree.
Containers own their child controls.
Some handlers/sources are owned; some are not.
Shutdown tears down the normal UI tree.
When in doubt, check the specific API.
Root lifetime
Declare the root globally or at EA scope.
MuiRoot g_ui;
Initialise it in OnInit and shut it down in OnDeinit.
int OnInit()
{
if(!g_ui.Init(ChartID(),0,"MyUI_",512,16))
return(INIT_FAILED);
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
g_ui.Shutdown();
}
Container ownership
Controls added to a container are owned by that container.
MuiPanel *panel=new MuiPanel();
parent.Add(panel);
When the parent/tree is destroyed, child controls are destroyed as part of the tree.
Fast wrapper ownership
Fast wrappers generally create controls and add them to the supplied parent.
Returned structs are handles, not separate ownership.
MuiSection section=Mui::Section(app.content,"Settings","");
MuiLabeledSpinEdit risk=Mui::LabeledSpinEdit(section.body,"Risk %",0.1,10.0,0.1,1.0);
The section and risk field live inside the UI tree. The returned structs let you access the pieces.
Handler ownership
Handler ownership varies.
Owned handler example:
button.SetHandler(new SaveHandler());
Non-owned handler example:
static MySelectionHandler s_handler;
table.SetSelectionChangedHandler(&s_handler);
Do not assume all handlers are owned or all handlers are non-owned.
Known handler patterns
| Area | Ownership pattern |
|---|---|
MuiButtonAction::SetHandler |
Owned |
ButtonRow button handlers |
Owned by each button |
ButtonGroup internal pick handlers |
Owned by each button |
| Selection/list/tree/table intent handlers | Not owned |
MuiTabs::SetHandler(MuiTabChangedHandler*) |
Owned |
MuiTabs::SetTabChangedHandler(...) |
Not owned |
MuiAccordion per-item SetOnToggle |
Owned |
MuiAccordion::SetExpandedChangedHandler |
Not owned |
Combo SetHandler(MuiComboItemHandler*) |
Owned |
MuiComboBoxHost::SetSelectionChangedHandler |
Not owned |
Dropdown SetMenuHandler |
Owned |
MuiDropdown::SetSelectionChangedHandler |
Not owned |
Date SetHandler(MuiDateChangedHandler*) |
Owned |
MuiDatePicker::SetDateChangedHandler(...) |
Not owned |
Dialog SetResultHandler |
Not owned |
Drawer SetStateChangedHandler |
Not owned |
Source ownership
List/table/tree controls usually reference sources without owning them.
For examples, static sources are common:
static MyTableSource source;
MuiTableView *table=Mui::TableView(parent,&source,520.0,260.0);
For heap sources, keep a clear owner and do not delete the source while the view uses it.
Simple helpers with sources
Mui::ListBox and Mui::SimpleTable allocate simple backing sources and expose the pointers.
Keep the wrapper value or source pointer if you plan to update rows.
MuiSimpleTable table=Mui::SimpleTable(parent,headers,4,0.0,180.0,true,true);
table.SetCell(0,0,"Started");
Native input hosts
Text boxes and text areas may create native chart objects.
g_ui.Shutdown() is important because it lets hosts remove those chart objects cleanly.
Common mistakes
Passing stack handlers into owned APIs
Avoid:
SaveHandler h;
button.SetHandler(&h);
Deleting controls owned by a container
If you added a control to a container, do not manually delete it unless the API explicitly says to remove/take ownership.
Deleting source objects too early
If a list/table references a source, the source must stay alive.
Treating returned wrapper structs as owners
Wrapper structs are access handles. They are not separate owners of the UI tree.