无法将 wxCommandEvent 绑定到处理程序,从 wxCommandEvent* 到 wxEvent* 的转换无效

发布于 2025-01-17 09:27:07 字数 1411 浏览 1 评论 0原文

我在使用 wxWidgets 3.1.5 时遇到了一个奇怪的问题。尝试将 wxCommandEvent 绑定到处理程序失败,并出现以下编译错误:

/usr/local/include/wx-3.1/wx/event.h:423:29: error: invalid conversion from ‘wxEventFunctorMethod<int, MainWindowPresenter, wxCommandEvent, MainWindowPresenter>::EventClass*’ {aka ‘wxEvent*’} to ‘wxCommandEvent*’ [-fpermissive]

根据 文档,明确提到将wxCommandEvent绑定到处理程序。这是 Bind 方法的签名,我真的很确定出了什么问题这里:

void MainWindow::addEventHandler(const std::string& windowName, const wxEventType eventType,
                                 void (MainWindowPresenter::*callback)(wxCommandEvent&), MainWindowPresenter &handler) {
    auto widget = findWindowByName<wxWindow>(windowName);
    widget->Bind(eventType, callback, &handler);
}

void MainWindow::registerEventHandlers(MainWindowPresenter& handler) {
    addEventHandler("readersListBox", wxEVT_LISTBOX, &MainWindowPresenter::onReaderSelected, handler);
}

Handler显然是一个接受的成员方法wxCommandEvent 参考:

void onReaderSelected(wxCommandEvent& event);

奇怪的是,它对于其他 wxEvent 子类型工作得很好。为什么这个不能编译?

I ran into a strange issue when using wxWidgets 3.1.5. Trying to bind wxCommandEvent to a handler fails with the following compiliation error:

/usr/local/include/wx-3.1/wx/event.h:423:29: error: invalid conversion from ‘wxEventFunctorMethod<int, MainWindowPresenter, wxCommandEvent, MainWindowPresenter>::EventClass*’ {aka ‘wxEvent*’} to ‘wxCommandEvent*’ [-fpermissive]

According to the documentation, binding wxCommandEvent to a handler is explicitly mentioned. Here's the signature of the Bind method, I'm really sure what is wrong here:

void MainWindow::addEventHandler(const std::string& windowName, const wxEventType eventType,
                                 void (MainWindowPresenter::*callback)(wxCommandEvent&), MainWindowPresenter &handler) {
    auto widget = findWindowByName<wxWindow>(windowName);
    widget->Bind(eventType, callback, &handler);
}

void MainWindow::registerEventHandlers(MainWindowPresenter& handler) {
    addEventHandler("readersListBox", wxEVT_LISTBOX, &MainWindowPresenter::onReaderSelected, handler);
}

Handler is obviously a member method accepting wxCommandEvent reference:

void onReaderSelected(wxCommandEvent& event);

Curiously, it works fine for other wxEvent subtypes. Why doesn't this compile?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

为了对列表框中的选择做出反应,您所需要做的就是以下操作:

class MainWindow : public wxFrame
{
public:
    MainWindow();
protected:
    void OnItemSelect(wxCommandEvent &event);
private:
    wxListBox *widget;
};

MainWindow::MainWindow() : wxFrame(...)
{
    widget = new wxListBox( this, wxID_ANY, /* rest of the parameters */);
    widget->Bind( wxEVT_LISTBOX, &MainWindow::OnItemSelect, this );
}

void MainWindow::OnItemSelect(wxCommandEvent &event)
{
// react on item selection
}

没有比这更简单的了。

现在您可以选择以非成员身份创建列表框。但是,您需要使用 dynamic_cast<>()wxDynamicCast() 确保小部件类型为 wxListBox,然后调用 Bind() 在强制转换的指针上。

像这样的事情:

MainWindow::MainWindow() : wxFrame()
{
    auto widget = wxDynamicCast( findWindowByName<wxWindow>(windowName), wxListBox );
    if( widget )
        widget->Bind( wxEVT_LISTBOX, &MainWindow::OnItemSelect, this );
}

顺便说一句,我希望你有一个合适的 findWindowByName<> 函数,因为所有 wx 调用都在开头使用大写字母。

另外,请确保不要使用智能指针来创建控件和主框架。 wxWidgets 是在 1990 年设计的,当时还没有使用智能指针,所以如果你这样做你会崩溃,因为窗口的析构函数会自动销毁它的所有子元素,但不会将指针置空,所以你会得到一个碰撞。

In order to react to the selection in the list box all you need to do is the following:

class MainWindow : public wxFrame
{
public:
    MainWindow();
protected:
    void OnItemSelect(wxCommandEvent &event);
private:
    wxListBox *widget;
};

MainWindow::MainWindow() : wxFrame(...)
{
    widget = new wxListBox( this, wxID_ANY, /* rest of the parameters */);
    widget->Bind( wxEVT_LISTBOX, &MainWindow::OnItemSelect, this );
}

void MainWindow::OnItemSelect(wxCommandEvent &event)
{
// react on item selection
}

It can't be simpler than this.

Now you can choose to create the listbox as not a member. Buit then you need to ensure that the widget type is wxListBox by using either dynamic_cast<>() or wxDynamicCast() and then call Bind() on casted pointer.

Something like this:

MainWindow::MainWindow() : wxFrame()
{
    auto widget = wxDynamicCast( findWindowByName<wxWindow>(windowName), wxListBox );
    if( widget )
        widget->Bind( wxEVT_LISTBOX, &MainWindow::OnItemSelect, this );
}

BTW, I hope you have an appropriate findWindowByName<> function, as all wx calls are using Capital letters in the beginning.

Also, make sure to not to use the smart pointer to create controls and main frame. wxWidgets is designed in 1990 when smart pointers were not used and so if you do you will get a crash, because the destructor of the windows will destroy all of its children automatically, but will not NULL-ify the pointer and so you will get a crash.

请别遗忘我 2025-01-24 09:27:07

bind()是使用事件类型(其第一个参数)的模板函数,以验证提供的事件处理程序实际上是通过使用wxeventtypetag&lt;&gt; 专业化而与之兼容的。给定的事件类型。在您的情况下,您只是将通用wxeventType传递给它,这使此检查失败。

最简单的解决方案可能是使您的addeventHandler()也使模板功能成为一个模板功能。如果这是不可能的或不希望的,则可以使用不同的bind()过载,例如,服用任意函数的人应起作用。

Bind() is a template function using the event type (its first argument) to verify that the event handler provided is actually compatible with it by using wxEventTypeTag<> specialization for the given event type. In your case you're just passing a generic wxEventType to it, which makes this check fail.

The simplest solution is probably to make your addEventHandler() a template function too. If this is impossible or undesirable, you can use a different Bind() overload, e.g. the one taking the arbitrary functor should work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文