【问题标题】:Unbinding a lambda event handler取消绑定 lambda 事件处理程序
【发布时间】:2017-10-05 14:03:23
【问题描述】:

如何取消绑定已绑定的事件处理程序,如下所示?

MyFrame::MyFrame()
{
    Bind(wxEVT_COMMAND_MENU_SELECTED,
         [](wxCommandEvent&) {
            // Do something useful
         },

         wxID_EXIT);
}

非常感谢您的第一个答案。我添加了一些额外的信息。

使用具体的 Functor 取消绑定事件处理程序的可能性已记录在案并且工作正常,但如果您使用 C++ 11 lambda 样式绑定某些东西,那么稍后将没有可用的 Functor 来调用 unbind 方法。如果相应的wxEvtHandler 应该被销毁,这会导致麻烦。

有没有“技巧”。 . .如果不是,我看不到使用 lambda 仿函数绑定的真实用例。 希望我错了。 . .

非常感谢
哈基

【问题讨论】:

  • @CamFerry,不,不是。解除绑定函数采用事件处理函数函数名称,这里没有带有 lambda 的名称。它可能在 C++11 中...

标签: c++ c++11 wxwidgets


【解决方案1】:

wxWidget's documentation 指定 Unbind 对函子(以及 lambdas)的确切工作方式:

目前仿函数是通过它们的地址进行比较的,不幸的是,如果将相同的地址用于两个不同的仿函数对象,则无法正常工作。

因此,如果您想可靠地Unbind 某个函子,您应该将函子保存在由BindUnbind 调用站点共享的特殊位置,然后将完全相同的对象传递给两个函数(尽管文档没有反映它,但他们仍接受const-references)。

这适用于 lambda 和仿函数,因此它甚至不是 C++11 特定的。如果你想Unbind 什么东西,这个东西在内存中应该有一个固定的地址。因此,它应该有一个名字。这在某种程度上扼杀了 lambda 的美感。

所以,这应该可行:

static auto event_handler = [](wxCommandEvent&) {
  // Do something
};
// ...
Bind(..., event_handler, ...);
// ...
Unbind(..., event_handler, ...);

但即使这样也不会(或确实如此,这取决于您对临时变量位置的运气):

struct EventHandler {
  void operator()(wxCommandEvent&) const {
    // Do something
  }
};
// ...
Bind(..., EventHandler(), ...);
// ...
Unbind(..., EventHandler(), ...);

【讨论】:

    【解决方案2】:

    不幸的是,目前没有办法做到这一点,你需要将你的 lambda 存储在一个对象中以赋予它一个身份,例如

    auto const handler = [](wxCommandEvent&) { ... };
    
    // To bind it:
    Bind(wxEVT_MENU, handler, wxID_EXIT);
    
    // To unbind it:
    Unbind(wxEVT_MENU, handler, wxID_EXIT);
    

    【讨论】:

      【解决方案3】:

      当程序完成执行时,所有事件处理程序将与所有控件解除绑定。即使对于 lambdas 也是如此。

      您很少需要在用户代码中取消绑定某些内容,但如果您这样做,@Caleth 的答案将起作用。

      【讨论】:

        【解决方案4】:

        作为您的示例,当对 Bind 的调用具有 lambda 时,您无法取消绑定。如果您存储 lambda,那么您可以取消绑定,例如

        class MyFrame 
        { 
            ... 
            std::function<void()> DoUnbind;
        }
        
        MyFrame::MyFrame()
        {
            auto DoSomethingUseful = [](wxCommandEvent&) {
                    // Do something useful
                 };
        
            Bind(wxEVT_COMMAND_MENU_SELECTED,
                 DoSomethingUseful,
                 wxID_EXIT);
        
            DoUnbind = [DoSomethingUseful](){
                Unbind(wxEVT_COMMAND_MENU_SELECTED,
                       DoSomethingUseful,
                       wxID_EXIT);
            };
        }
        

        【讨论】:

        • 为什么会这样?根据 cmets here,您必须使用函子的地址来解除绑定。你是按值捕获的,所以DoUnbind 有一个新的 lambda 副本,它的地址与最初绑定的地址不同。
        猜你喜欢
        • 2010-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-05
        • 2013-01-27
        相关资源
        最近更新 更多