Description
Ok, so I have an array of buttons. Well, actually it is a vector, and could be any size. So wxWidgets usually recommends static event handlers and using dynamic event handlers was really confusing.
So I have the wxWidgets book, I researched the website and found the Connect()
function.
So I have a class called wxDieFrm (because I was creating dice). This wxDieFrm object has the following code snippet to create dynamic events for each button. So I incorrectly figured I would use the wxButton.Connect()
method. Let me show what I did wrong and then how easily it was fixed.
for (int i = 0; i < mSetOfDice->getNumberOfDice(); i++)
{
// Some code here...
wxButton *rollButton = new wxButton(this, *buttonID, wxT("Roll"), wxPoint(5, 15), wxSize(75, 25), 0, wxDefaultValidator, wxT("buttonRoll"));
//The following line is incorrect and the cause of the problem
rollButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxDieFrm::buttonRollClick) );
WxBoxSizer->Add(rollButton,0,wxALIGN_CENTER | wxALL,5);
}
Notice I commented just before the problem line, so you would know the cause.
Then the event functions is this:
/*
* buttonRollClick
*/
void wxDieFrm::buttonRollClick(wxCommandEvent& event)
{
wxButton *button = (wxButton*)event.GetEventObject();
int id = button->GetId() - 4001;
int rollValue = mSetOfDice->getDie(id).roll();
wxBitmap *bmp = mBitmapVector->at(rollValue - 1);
mDice->at(id)->SetBitmap(*bmp);
}
Problem
This didn’t work. I got all kinds of access violation errors, which was strange to me, because being in the wxDieFrm::buttonRollClick()
function, the entire wxDieFrm should have been accessible. But nothing I did could and no amount of debugging helped me figure out this. It took reading a bunch of different posts before I finally found the answer.
Cause
There was really only one problem. I was having the button call its Connect()
method. This was a problem because when the code went to the wxDieFrm::buttonRollClick()
in that it only allowed me access to my button object.
Resolution
The fix was simple, don’t call Connect() from the button, just call it using the wxDieFrm object.
for (int i = 0; i < mSetOfDice->getNumberOfDice(); i++)
{
// Some code here...
wxButton *rollButton = new wxButton(this, *buttonID, wxT("Roll"), wxPoint(5, 15), wxSize(75, 25), 0, wxDefaultValidator, wxT("buttonRoll"));
WxBoxSizer->Add(rollButton,0,wxALIGN_CENTER | wxALL,5);
}
//The following line is THE CORRECT VERSION and the RESOLUTION to the problem
Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxDieFrm::buttonRollClick) );
Reference Material
The following are the resources and different articles I had to pore over to finally reach this understanding:
Chapter 2 of the WxWidgets book, the event handler section.
Chapter 7 of the WxWidgets book.
http://wiki.wxwidgets.org/Events#Using_Connect.28.29
http://wiki.wxwidgets.org/Example_Of_Using_Connect_For_Events
http://wxwidgets.blogspot.com/2007/01/in-praise-of-connect.html
http://wiki.wxwidgets.org/Using_Connect_To_Add_Events_To_An_Existing_Class
The funniest part is the last one has a big post that says THE REST OF THIS PAGE IS WRONG and so I passed over it a half dozen times, before finally reading it. It was actually the one that gave me the answer under the diagnosing the problem section, it reads:
So my experiment reveals a characteristic of wxEvtHandler::Connect that is not explicitly documented (though it may be obvious to those who actually know C++): the wxObjectEventFunction passed to Connect() will be called with this
set to whatever called Connect().
So by calling wxButton.Connect()
instead of wxDieFrm.Connect()
(or this.Connect()
or just Connect()
) the value of this
(the code word this not the preposition) was the wxButton and not wxDieFrm. That is why i was getting access violations.
So as soon as I switched to wxDieFrm.Connect()
the value of this
because my wxDieFrm and my access violations went away and everything works. For a minute I considered dropping wxWidgets altogether, but now that I understand this features, I like wxWidgets much more than ever.