set user data for ribbonbuttonbar event

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
shawnee
Experienced Solver
Experienced Solver
Posts: 78
Joined: Tue Jan 16, 2018 1:05 am

set user data for ribbonbuttonbar event

Post by shawnee »

I'm using wxWidgets 3.1, I got a crash problem if I pass userdata to wxEVT_RIBBONBUTTONBAR_CLICKED event callback.
I used dynamic event binding and run under Debug mode.

Here is my example codes:

Code: Select all

#define wxID_App_TEST   100000
///////////////////////////////////
class myFrame : public wxFrame {
private:
  int   user_id;

private:
  wxRibbonBar  *create_ribbon();
  wxRibbonBar * ribbbon;

private:
  void OnClick(wxRibbonButtonBarEvent & event);

public:
  myFrame():wxFrame(NULL, wxID_ANY, "test", wxDefaultPosition, wxSize(800, 450), wxDEFAULT_FRAME_STYLE | wxSUNKEN_BORDER) {
    this->ribbon = NULL;
    this->user_id= 0;

    this->ribbbon = this->create_ribbon();
  }
 ~myFrame();
};

wxRibbonBar *myFrame::create_ribbon()
{
  wxRibbonBar * rbar = new wxRibbonBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
                                                             wxRIBBON_BAR_FLOW_HORIZONTAL | wxRIBBON_BAR_SHOW_PAGE_LABELS);
      wxRibbonPage *pApplication = new wxRibbonPage(this->ribbbon, wxID_ANY, "Application", wxNullBitmap);
          wxRibbonPanel *pApplicationPanel = new wxRibbonPanel(pApplication , wxID_ANY, "Test", wxNullBitmap,
                                                                                             wxDefaultPosition, wxDefaultSize, wxRIBBON_PANEL_NO_AUTO_MINIMISE);
              wxRibbonButtonBar *pAppTestBar = new wxRibbonButtonBar(pApplicationPanel);
                  pAppTestBar->AddButton(wxID_App_TEST, "Test", wxArtProvider::GetBitmap(wxART_QUESTION, wxART_TOOLBAR, wxSize(48,48)));
  
  this->ribbbon->Realize();
  
  Bind(wxEVT_RIBBONBUTTONBAR_CLICKED, &myFrame ::OnClick, this, wxID_App_TEST, wxID_ANY, this);

  return rbar;
}

void myFrame::OnClick(wxRibbonButtonBarEvent& event)
{
    //@@preconditions
    //@@end preconditions

    myFrame* userdata = static_cast<myFrame*>(event.GetEventUserData()); assert(userdata);
    userdata->user_id = 1000;
}
Other necessary codes are ignored, let we just focus on the major parts.
My problem is the program will crash, the crash point in the ~myFrame()!

If I don't pass userdata in Bind function(Bind(wxEVT_RIBBONBUTTONBAR_CLICKED, &myFrame ::OnClick, this, wxID_App_TEST)), then no crash. But pass userdata is really important to me.

Is there somebody could help me? Thanks!
Last edited by doublemax on Tue Jan 16, 2018 6:11 am, edited 1 time in total.
Reason: Added code tags
User avatar
doublemax
Moderator
Moderator
Posts: 19162
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: set user data for ribbonbuttonbar event

Post by doublemax »

The documentation for userData says:
userData
Optional data to be associated with the event table entry. wxWidgets will take ownership of this pointer, i.e. it will be destroyed when the event handler is disconnected or at the program termination. This pointer can be retrieved using wxEvent::GetEventUserData() later.
So you can't use it in the way you did. But in the event handler you have access to "myFrame" anyway, so do you really need it?
Use the source, Luke!
shawnee
Experienced Solver
Experienced Solver
Posts: 78
Joined: Tue Jan 16, 2018 1:05 am

Re: set user data for ribbonbuttonbar event

Post by shawnee »

I find out the way from this post: viewtopic.php?f=1&t=39934&p=161254&hili ... ta#p161249

template<class T>
class wxExUserData : public wxObject {
public:
T * Class() { return cls; }

private:
T * cls;

public:
wxExUserData(T * cl) : cls(cl) {}
virtual ~wxExUserData() {};
};


at Bind point, change code to this:
Bind(wxEVT_RIBBONBUTTONBAR_CLICKED, &myFrame ::OnClick, this, wxID_App_TEST, wxID_ANY, new wxUserData<myFrame>(this));

in callback function, code changed like this:
void myFrame::OnClick(wxRibbonButtonBarEvent& event)
{
//@@preconditions
//@@end preconditions

wxUserData<myFrame> * userdata = static_cast<wxUserData<myFrame> *>(event.GetEventUserData()); assert(userdata);
myFrame* frm = userdata ->Class();
frm->user_id = 1000;
}


then nothing happens when program exit!
shawnee
Experienced Solver
Experienced Solver
Posts: 78
Joined: Tue Jan 16, 2018 1:05 am

Re: set user data for ribbonbuttonbar event

Post by shawnee »

doublemax wrote:The documentation for userData says:
userData
Optional data to be associated with the event table entry. wxWidgets will take ownership of this pointer, i.e. it will be destroyed when the event handler is disconnected or at the program termination. This pointer can be retrieved using wxEvent::GetEventUserData() later.
So you can't use it in the way you did. But in the event handler you have access to "myFrame" anyway, so do you really need it?
Yes, passing "myFrame" class pointer as user data looks weird here, just ignore it. If we pass other object class not itself, the dynamic event binding is more powerful. :D
Post Reply