Home > OS >  Cannot bind wxCommandEvent to a handler, invalid conversion from wxCommandEvent* to wxEvent*
Cannot bind wxCommandEvent to a handler, invalid conversion from wxCommandEvent* to wxEvent*

Time:03-29

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?

CodePudding user response:

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.

CodePudding user response:

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.

  • Related