c++ - wxWidgets:在触发时取消绑定(bind)事件

标签 c++ wxwidgets

我正在编写一个 wxWidgets GUI,其中涉及通过按钮动态添加和删除 gridsizer 内的控件行。

每行控件都有一个“删除”按钮,该按钮会触发以下事件:

  • 从其大小调整器中删除控件
  • 隐藏控件
  • 解除绑定(bind)删除按钮事件
  • 将控件标记为可重用控件池中可用(我是 重用控件,因为 wxWidgets 不喜欢删除以下内容 运行时)

现在我不认为在事件处理程序本身内解除事件绑定(bind)是一件好事。有没有更好的方法来实现这种行为?

这就是我动态创建控件的方式

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);
}

这是事件处理程序:

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);
}

顺便说一句,此 GUI 的目的是为加载的 XML 文件中的属性添加搜索过滤器。

最佳答案

将事件与其处理程序解除绑定(bind)很好,我确实没有看到这样做有任何问题,甚至是潜在的问题。

而且,一般来说,wxWidgets 在运行时删除控件方面没有任何特殊问题,并且使用隐藏控件池似乎比仅仅删除并根据需要重新创建它们更麻烦。但是,从该控件生成的事件的处理程序中删除该控件确实是一个坏主意,并且可能会导致崩溃。对此的规范解决方案是立即隐藏控件并“稍后”删除它,即在下一个事件循环迭代期间。这可以通过在所有版本的 wxWidgets 中显式使用 wxEVT_IDLE 来完成,或者更方便地使用 CallAfter() 来完成。在 wxWidgets 2.9.5 或更高版本中。

关于c++ - wxWidgets:在触发时取消绑定(bind)事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18955287/

相关文章:

python - wxPython:如何将一个面板放在另一个面板上

c++ - 如何为 win32 构建 wxmathPlot?

c++ - 在 wxFrame 上处理来自 wxTextCtrl 的事件 - C++/wxWidgets

c++ - 在 CLion (Ubuntu) 上构建 wxWidgets 3.1.0

c++ - 让 WinVerifyTrust 使用目录签名文件,例如 cmd.exe

c++ - 在 C++ STL 中使用 auto 关键字

c++ - 强制沿长链调用基类虚函数

c++ - 不使用模板时的编译错误[opencv]

C++ 元组类型到函数参数类型

c++ - 构建wxWidgets Hello world