2

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?

1 Answers1

2

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);
    }
}

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.

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

ids [i] = wxNewId();

The MainFrame::OnPress method could look like this:

void MainFrame::OnPress(wxCommandEvent& event)
{
    long firstID = *theStep16->GetIDs();

    switch(event.GetId() - firstID)
    {
        case 0:
            std::cout << "First button" << std::endl;
            break;
        case 1:
            std::cout << "Second button" << std::endl;
            break;
        default:
            std::cout << "One of the other buttons with ID " 
                      << event.GetId() << std::endl;
    }
}
iwbnwif
  • 327
  • 2
  • 13
  • I ended up just using Connect(), as in:sequencer[i]->Connect(wxEVT_BUTTON, wxCommandEventHandler(Beacon_UIFrame::OnButton)); – Matthias Quintero Aug 29 '16 at 20:09
  • Is Bind() faster in any way? or are there any major advantages to it? – Matthias Quintero Aug 29 '16 at 20:10
  • 2
    The accepted answer to [this](http://stackoverflow.com/questions/21654064/wxwidgets-event-table-vs-connect) question is probably the most succinct description of the advantages. – iwbnwif Aug 29 '16 at 20:17
  • 1
    You don't really needs `ids` array at all when using `Bind()`, just pass `wxID_ANY` directly to `wxButton` ctor. You also don't need to pass `GetId()` as the last argument of `Bind()`, when you're binding to the events on the button itself you're only ever going to receive the events for this button. – VZ. Aug 29 '16 at 23:46
  • @VZ I assumed that the `ids` array was to differentiate between the various buttons in a single event handler. Thank you though for picking up about not needing `GetId()` in the `Bind()` call. I have updated my answer to hopefully improve on both these points. – iwbnwif Aug 30 '16 at 07:13
  • Yes, you're right, I didn't think of using `ids` in the event handler itself, sorry. In principle you could still avoid them and use `event.GetEventObject()`, but if the buttons are all similar (e.g. digits on a calculator or something like this), then IDs are a simpler way to deal with this. – VZ. Aug 30 '16 at 13:22