Search code examples
c++wxwidgets

Can somebody help me with EventHandling on WXWidgets


while trying to make some first progress with WXWidgets in C++ I´ve got on a problem.

As youre able to see in the Code below, I´m trying to Handle an Button-Click-Event from an WXWidget-Application.

The main Problem is that the dedicated Method TopPanel::OnClick() doesnt run. (Nothing is print to console)

Possible Errors:

  • Problem with my implementation of PanelEvents
  • Wrongly installed WXWidgets (probably not cuz it does compile without any errors)
#include <wx/wx.h>

class App : public wxApp
{
public:
    virtual bool OnInit();
};

class MainFrame : public wxFrame
{
public:
    MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
};

class TopPanel : public wxPanel
{
public:
    TopPanel(wxWindow* parent, wxSize size);
private:
    void OnClick(wxCommandEvent &);
    wxDECLARE_EVENT_TABLE();
};

enum ButtonID {
    button_id_first = wxID_LAST + 1,
    button_id_other
};

bool App::OnInit()
{
    MainFrame* frame = new MainFrame("Nova Loader", wxDefaultPosition, wxDefaultSize);
    frame->Show(true);
    return true;
}

wxIMPLEMENT_APP(App);

MainFrame::MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(nullptr, wxID_ANY, title, pos, size)
{
    this->SetBackgroundColour(wxColor(25, 25, 25));
    this->SetFocus();

    TopPanel* pnl_top = new TopPanel(this, wxSize(500, 30));
    wxPanel* pnl_bottom = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(500, 270));
    wxButton* btn_load = new wxButton(pnl_top, button_id_first, "Load");
    wxButton* btn_exit = new wxButton(pnl_top, button_id_other, "Exit");
    wxBoxSizer* s1 = new wxBoxSizer(wxVERTICAL);
    s1->Add(pnl_top, 0, wxALL, 5);
    s1->Add(pnl_bottom, 1, wxALL, 5);

    wxBoxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
    s2->Add(btn_load, 0, wxRIGHT, 5);
    s2->Add(btn_exit, 0);

    wxBoxSizer* s3 = new wxBoxSizer(wxVERTICAL);
    s3->Add(s2, 0, wxALIGN_RIGHT | wxRIGHT | wxTOP, 3);

    pnl_top->SetSizer(s3);
    pnl_bottom->SetBackgroundColour(wxColor(45, 45, 45));

    this->SetSizerAndFit(s1);
}

TopPanel::TopPanel(wxWindow* parent, wxSize size) : wxPanel(parent, wxID_ANY, wxDefaultPosition, size)
{
    this->SetSize(500, 30);
    this->SetId(wxID_ANY);
    this->SetBackgroundColour(wxColor(45, 45, 45));
}

void TopPanel::OnClick(wxCommandEvent &e)
{
    std::cout << e.GetId() << std::endl;
}

wxBEGIN_EVENT_TABLE(TopPanel, wxPanel)
EVT_BUTTON(button_id_first, TopPanel::OnClick)
EVT_BUTTON(button_id_other, TopPanel::OnClick)
wxEND_EVENT_TABLE()

Thanks to everyone trying to help me!

~ Tim


Solution

  • First things first, your given example successfully calls the OnClick method. So your claim that OnClick is not called is not correct.

    Now that being said, with newer(modern) wxWidgets you can also use dynamic event table using Bind instead of static event table as shown below. The changes made are highlighted as comments in the below given program:

    class TopPanel : public wxPanel
    {
    public:
        TopPanel(wxWindow* parent, wxSize size);
        void OnClick(wxCommandEvent &);
        //removed wxdeclare_event_table from here as no longer needed 
    };
    MainFrame::MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(nullptr, wxID_ANY, title, pos, size)
    {
        //other code as before
    //---------------------------------------------vvvvvvvv----------->let wxwidgets choose the id for you 
        wxButton* btn_load = new wxButton(pnl_top, wxID_ANY, "Load");
        //bind btn_load to onClick 
        btn_load->Bind(wxEVT_BUTTON, &TopPanel::OnClick, pnl_top);
    //---------------------------------------------vvvvvvvv------------>let wxwidgets choose the id for you
        wxButton* btn_exit = new wxButton(pnl_top, wxID_ANY, "Exit");
        //bind btn_exit to onclick 
        btn_exit->Bind(wxEVT_BUTTON, &TopPanel::OnClick, pnl_top);
        //other code as before
    }
    

    Below is the complete working example that uses Bind:

    #include <wx/wx.h>
    
    class App : public wxApp
    {
    public:
        virtual bool OnInit();
    };
    
    class MainFrame : public wxFrame
    {
    public:
        MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
    };
    
    class TopPanel : public wxPanel
    {
    public:
        TopPanel(wxWindow* parent, wxSize size);
        void OnClick(wxCommandEvent &);
        //removed wxdeclare_event_table from here as no longer needed 
    };
    
    enum ButtonID {
        button_id_first = wxID_LAST + 1,
        button_id_other
    };
    
    bool App::OnInit()
    {
        MainFrame* frame = new MainFrame("Nova Loader", wxDefaultPosition, wxDefaultSize);
        frame->Show(true);
        return true;
    }
    
    wxIMPLEMENT_APP(App);
    
    MainFrame::MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(nullptr, wxID_ANY, title, pos, size)
    {
        this->SetBackgroundColour(wxColor(25, 25, 25));
        this->SetFocus();
    
        TopPanel* pnl_top = new TopPanel(this, wxSize(500, 30));
        wxPanel* pnl_bottom = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(500, 270));
    //---------------------------------------------vvvvvvvv----------->let wxwidgets choose the id for you 
        wxButton* btn_load = new wxButton(pnl_top, wxID_ANY, "Load");
        //bind btn_load to onClick 
        btn_load->Bind(wxEVT_BUTTON, &TopPanel::OnClick, pnl_top);
        wxButton* btn_exit = new wxButton(pnl_top, wxID_ANY, "Exit");
        //bind btn_exit to onclick 
        btn_exit->Bind(wxEVT_BUTTON, &TopPanel::OnClick, pnl_top);
        wxBoxSizer* s1 = new wxBoxSizer(wxVERTICAL);
        s1->Add(pnl_top, 0, wxALL, 5);
        s1->Add(pnl_bottom, 1, wxALL, 5);
    
        wxBoxSizer* s2 = new wxBoxSizer(wxHORIZONTAL);
        s2->Add(btn_load, 0, wxRIGHT, 5);
        s2->Add(btn_exit, 0);
    
        wxBoxSizer* s3 = new wxBoxSizer(wxVERTICAL);
        s3->Add(s2, 0, wxALIGN_RIGHT | wxRIGHT | wxTOP, 3);
    
        pnl_top->SetSizer(s3);
        pnl_bottom->SetBackgroundColour(wxColor(45, 45, 45));
    
        this->SetSizerAndFit(s1);
    }
    
    TopPanel::TopPanel(wxWindow* parent, wxSize size) : wxPanel(parent, wxID_ANY, wxDefaultPosition, size)
    {
        this->SetSize(500, 30);
        this->SetId(wxID_ANY);
        this->SetBackgroundColour(wxColor(45, 45, 45));
    }
    
    void TopPanel::OnClick(wxCommandEvent &e)
    {
        std::cout << e.GetId() << std::endl;
        std::cout<<"toppanel onclick called"<<std::endl;
    }
    //no need for event table entries here