I'm coding a wxWidgets GUI that involves dynamically adding and removing rows of controls inside a gridsizer through buttons.
Each row of controls has a "remove" button that triggers an event that:
- Removes the controls from their sizer
- Hides the controls
- Unbinds theremove button event
- Flags the controls as available in the reusable controls pools (I'm re-using controls because wxWidgets doesn't like deleting stuff at runtime)
Now I don't think unbinding the event inside the event handler itself is a good thing. Is there a better way to achieve this behaviour?
this is how I dynamically create my controls
bool filtermanager::add()
{
if (!grid || !box || !form || !bsizer)
return false;
dbgcode(log->d(tag, "add: adding a new filter row"));
// add and index filter in the filter map and refresh layout
filter *flt = new filter(this, box, grid);
filters[flt->removebutton()->GetId()] = flt;
refreshlayout();
return true;
}
filtermanager::filter::filter(filtermanager *parent,
wxStaticBox *box, wxGridSizer *grid)
: parent(parent), grid(grid)
{
controlpool *ctl = parent->ctl;
// initialize filter row elements
property = ctl->makeComboBox(box, "property");
value = ctl->makeTextCtrl(box, "value");
button = ctl->makeButton(box, "Remove");
// add filter row to the grid sizer
grid->SetRows(grid->GetRows() + 1);
grid->Add(property, 0, wxALL | wxEXPAND, 0);
grid->Add(value, 0, wxALL | wxEXPAND, 0);
grid->Add(button, 0, wxALL | wxEXPAND, 0);
// bind remove button
button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &filtermanager::OnRemoveClicked, parent);
}
this is the event handler:
void filtermanager::OnRemoveClicked(wxCommandEvent &e)
{
wxButton *b = dynamic_cast<wxButton *>(e.GetEventObject());
filter *flt = filters[b->GetId()];
dbgcode(log->d(tag,
strfmt() << "OnRemoveClicked: remove button event caught" <<
" property=" << flt->propertycombo() <<
" value=" << flt->valuetext() <<
" button=" << flt->removebutton())
);
removebyflt(flt);
}
void filtermanager::removebyflt(filter *flt)
{
int id = flt->id();
// dealloc filter from the map
delete filters[id];
filters[id] = NULL;
filters.erase(id);
}
filtermanager::filter::~filter()
{
controlpool *ctl = parent->ctl;
// unbind button
button->Unbind(wxEVT_COMMAND_BUTTON_CLICKED, &filtermanager::OnRemoveClicked, parent);
// remove the filter from the gui
if (!grid->Detach(property))
parent->log->e(tag, "~filter: failed to remove property from sizer");
if (!grid->Detach(value))
parent->log->e(tag, "~filter: failed to remove value from sizer");
if (!grid->Detach(button))
parent->log->e(tag, "~filter: failed to remove button from sizer");
grid->SetRows(grid->GetRows() - 1);
// refresh panels as usual
parent->refreshlayout();
ctl->free(property);
ctl->free(value);
ctl->free(button);
}
By the way, the purpose of this GUI is adding search filters for properties in a loaded XML file.