Matthias Quintero Matthias Quintero - 3 months ago 18
C++ Question

How to add commands to buttons created from within a class in wxwidgets?

I have searched far and wide and thought different options for quite a while, and am now absolutely stumped. I created a simple class that makes 16 buttons and assigns IDs to them in the constructor. I would like each of the buttons to have an event triggered when clicked.

Class in the header:

class step16
{
///signals and buttons
private:
wxButton* sequencer [16];
long* ids = new long[16];
public:
step16(wxFrame* frame);
~step16();
};


Declaration of the functions in the source file:

///constructor for 16 step sample sequencer class
step16::step16(wxFrame* frame)
{
///clear all signals on initialization and create buttons
for(int i = 0; i < 16; i++){
ids [i] = wxNewId();
sequencer[i] = new wxButton(frame,ids[i],wxString::Format(_("")),
wxPoint(i*30 , 0,wxSize(30,20) );
}
}

///destructor for the 16 step sequencer class
step16::~step16(){delete[]signals;}


The only way I know how to add click events to buttons in wxWidgets is using the Connect() method in the initialization part of the Main wxFrame, but connecting them in that part of the program would not bring the desired results. Mainly because I need a new set of 16 buttons with unique IDs and events in every instance of the step16 class. How would I go about adding unique click events to each of these buttons?

Answer

You can use Bind to bind a handler in any class that is derived from wxEventHandler (i.e. just about any standard wxWidgets class, including wxFrame).

Pass the ID of the button to the Bind() call so your event handler knows which button has been pressed.

For example your step16 constructor could look like this:

///constructor for 16 step sample sequencer class
step16::step16(wxFrame* frame)
{
    ///clear all signals on initialization and create buttons
    for(int i = 0; i < 16; i++)
    {
        ids      [i] = wxNewId();
        sequencer[i] = new wxButton(frame,ids[i],wxString::Format(_("")),
                                        wxPoint(i*30,0), wxSize(30,20));

        /// Add it to something so I can test this works!
        frame->GetSizer()->Add(sequencer[i]);

        /// Bind the clicked event for this button to a handler 
        /// in the Main Frame.
        sequencer[i]->Bind(wxEVT_COMMAND_BUTTON_CLICKED, 
                            &MainFrame::OnPress, 
                            (MainFrame*)frame, 
                            sequencer[i]->GetId());
    }
}

In this example, I have created the event handler in the MainFrame class, a pointer to an instance of which is passed to ctor for step16.

The MainFrame::OnPress method looks like this:

void MainFrame::OnPress(wxCommandEvent& event)
{
    std::cout << "Event ID is " << event.GetId() << std::endl;
}

You can distinguish between the button presses using event.GetId() which will be the value set by the line:

ids [i] = wxNewId();
Comments