Search code examples
c++eventswxwidgets

How should I change my code so that I can call the Bind() function instead of using the event table?


I am using WxWidgets 3.2 for my C++ Windows application.

I need to pass data (eg login) from one class to another. To do this, I create a custom event and use the event table to bind the event to the handler.

For example, I have a LoginPanel class and I want to pass the login entered by the user to another class - MainFrame.

LoginPanel.h

DECLARE_EVENT_TYPE(LOGIN_ENTERED, wxCommandEvent)

enum class Buttons_ID {
    ID_CONNECT_BUTTON = wxID_HIGHEST + 1,
};

class LoginPanel : public wxPanel {
public:
    LoginPanel(wxWindow* parent, wxWindowID id = wxID_ANY);

private:
    void OnConnectButton(wxCommandEvent& event);
    wxTextCtrl* usernameInput;
};

LoginPanel.cpp

DEFINE_EVENT_TYPE(LOGIN_ENTERED)
LoginPanel::LoginPanel(wxWindow* parent, wxWindowID id)
    : wxPanel(parent, id) {
    wxButton* connectButton = new wxButton(loginTab, wxID_ANY, "Connect");
    connectButton->Bind(wxEVT_BUTTON, &LoginPanel::OnConnectButton, this);
}

void LoginPanel::OnConnectButton(wxCommandEvent& event) {
    wxString username = usernameInput->GetValue();
    wxCommandEvent loginEvent(LOGIN_ENTERED, GetId());
    loginEvent.SetString(username);
    GetParent()->GetEventHandler()->ProcessEvent(loginEvent);
}

MainFrame.h

class MainFrame : public wxFrame {
public:
    MainFrame(const wxString& title);
    ~MainFrame();

private:
    LoginPanel * loginPanel;           

public:
    void ShowLoginPanel();
    void OnLoginEntered(wxCommandEvent& event);
    wxDECLARE_EVENT_TABLE(); 
};

MainFrame.cpp

wxBEGIN_EVENT_TABLE(ChessFrame, wxFrame)                             
    EVT_COMMAND(wxID_ANY, LOGIN_ENTERED, ChessFrame::OnLoginEntered) 
wxEND_EVENT_TABLE()                                                  

MainFrameFrame::MainFrameFrame(const wxString& title)
    : wxFrame(nullptr, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~wxRESIZE_BORDER) {
    wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);

    loginPanel = new LoginPanel(this, wxID_ANY);
    mainSizer->Add(loginPanel, 1, wxEXPAND);
    SetSizer(mainSizer);
    ShowLoginPanel();
}

void MainFrameFrame::OnLoginEntered(wxCommandEvent& event) {
    auto login = event.GetString();
}

This is how the code works and the LOGIN_ENTERED event is normally passed from the LoginPanel class to the OnConnectButton() handler of the MainFrame class.

Since using the event table is not very modern now, I want to use the Bind() function. I call the Bind() function in the constructor of the MainFrame class:

loginPanel->Bind(LOGIN_ENTERED, &ChessFrame::OnLoginEntered, this);

However, the problem is that an error occurs:

C2664: 'void wxEventFunctorMethod<EventTag,ChessFrame,EventArg,EventHandler>::CheckHandlerArgument(EventArg *)': cannot convert argument 1 from 'wxEvent *' to 'EventArg *'

How should I change my code so that I can call the Bind() function instead of using the event table?


Solution

  • I think the main issue is the macro you're using to declare/define your new events. You should use wxDECLARE_EVENT and wxDEFINE_EVENT instead.

    In short, change

    DECLARE_EVENT_TYPE(LOGIN_ENTERED, wxCommandEvent)
    

    to

    wxDECLARE_EVENT(LOGIN_ENTERED, wxCommandEvent);
    

    and

    DEFINE_EVENT_TYPE(LOGIN_ENTERED)
    

    to

    wxDEFINE_EVENT(LOGIN_ENTERED, wxCommandEvent);
    

    Also, I would suggest changing

    GetParent()->GetEventHandler()->ProcessEvent(loginEvent);
    

    to simply

    ProcessWindowEvent(loginEvent);
    

    Command events will filter up to the parent windows if not handled by the window itself.