【问题标题】:wxWidgets: unbind event as its triggeredwxWidgets:解除绑定事件作为其触发
【发布时间】:2013-09-23 08:56:30
【问题描述】:

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

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

  • 从它们的 sizer 中删除控件
  • 隐藏控件
  • 解除绑定删除按钮事件
  • 将控件标记为可重用控件池中的可用控件(我是 重用控件,因为 wxWidgets 不喜欢在 运行时)

现在我不认为在事件处理程序本身中取消绑定事件是一件好事。有没有更好的方法来实现这种行为?

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

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 文件中的属性添加搜索过滤器。

【问题讨论】:

  • 只有事件处理程序知道按钮何时被按下,所以只有事件处理程序才能解除绑定。另一种选择是在某处设置一个标志,该标志确定事件是否得到处理

标签: c++ wxwidgets


【解决方案1】:

从它的处理程序中解除绑定事件很好,我真的没有看到任何问题,即使是潜在的,这样做。

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

【讨论】:

  • 谢谢!关于在运行时删除控件,wxWidgets 不是自己管理基于 wxWindow 的类,以便自动删除它们吗?在运行时删除控件时这不是问题吗?
  • wxWidgets 将在父窗口被销毁时删除所有子窗口(我们说子窗口归其父窗口所有),因此您不必必须这样做。但如果需要,您仍然可以自行删除它们。
猜你喜欢
  • 2020-12-10
  • 2015-06-25
  • 1970-01-01
  • 1970-01-01
  • 2020-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多