Date: Thu, 18 Nov 1993 11:15:44 +0200 From: Syst{ Kari Message-Id: <199311180915.AA06005@karikukko.cs.tut.fi> To: wxwin-users@ed.aiai, tane@fi.uta.cs Subject: Re: member function as wxFunction > > is it true that i can't use a member function of a class as a callback > > function? > > Yes, unless you declare your member function as static. But then you > don't have this-pointer available in your function. There is actually a way. The I first define a new button class: void my_text_callback (wxObject &obj, wxEvent &ev); // The typedef for a callback member. // I found something like this from the Solbource OI include files, // I just copied it without fully understanding the corresponding // C++ rule. typedef void (wxObject::callback_member_func)(...); // A class with a possibility to send callback method calls to other // objects/ class MyButton: public wxButton { public: wxObject *client_obj; callback_member_func* mem_func; MyButton(wxPanel *panel, wxObject *client, callback_member_func *mem, char *label) : wxButton(panel, my_text_callback, label) { client_obj = client; mem_func = mem; }; }; void my_text_callback (wxObject &obj, wxEvent &ev) { /* This is a terrible glude. The member 'mem_func' should should defined at the top of inheritance hierarchy */ MyButton &o = (MyButton &) obj; wxObject *to = o.client_obj; (to->*(o.mem_func))(obj,ev); }; Now, I can set a call back which is a object+method pair (see "new MyButton"): #include #include #include "mybutton.h" wxText *text; class MyText: public wxText { // A new class with a call-back method int n; static char *toolkits[4]; public: MyText(wxPanel *p, wxFunction f, char *l) : wxText(p,f,l) { n = 0; this->SetValue(toolkits[0]); }; void Inc() { ++n; if (n >= sizeof(toolkits) / sizeof(toolkits[0])) n = 0; this->SetValue(toolkits[n]); } }; char *MyText::toolkits[4] = {"wxwin", "uit", "oi", "interviews"}; class MyApp: public wxApp { public: wxFrame *OnInit() { wxFrame *frame = new wxFrame(NULL,"Button test"); wxPanel *panel = new wxPanel(frame); text = new MyText(panel, NULL,"Toolkit"); panel->NewLine(); new MyButton(panel, text, &MyText::Inc, "Push Me2"); frame->Show(TRUE); return frame; }; } myApp; From: Burell David Kingery Message-Id: <9312171452.AA05907@clavin> Subject: wxWindows code sample To: Craig Cockburn Date: Fri, 17 Dec 1993 08:59:15 -0600 (CST) Craig, Here is the first code sample I promised. It is a list dialog which can swap between two different lists. In my application I use it to swap between active and inactive employees (those still working and those who aren't). It is a good example of how to use static member functions as wxFunctions for callbacks. Here is the .h file for the list dialog. I have added comments where I thought they were appropriate so search for //= to find them. Hope this helps, David ================================ CODE STARTS HERE ========================== /* listdiag.h */ #ifndef LISTDIAG_H #define LISTDIAG_H class ListDialog { public: ListDialog(wxFrame *parent, int x, int y, char *message, char *caption, int count1, char *list1[], int count2, char *list2[], char **choice, int *index); ~ListDialog(void); private: wxDialogBox *dialog; wxListBox *listbox; wxButton *list_select; char *the_selection; int the_index; int visible_list; int c1; char **l1; int c2; char **l2; //= // Here are the three member functions which actually do the work I want // when the callback is invoked. Since these are member functions they // will have access to the instance data of the object. void OkCallback(void); void CancelCallback(void); void ListSelectCallback(void); //= // Here are three static member functions which are the initial callbacks // of the class. These are invoked in the normal manner for wxWindows. static void OnOk(wxObject& the_object, wxEvent& the_event); static void OnCancel(wxObject& the_object, wxEvent& the_event); static void OnListSelect(wxObject& the_object, wxEvent& the_event); }; #endif Now here is the .cc file for the list dialog. I'm not real sure if you could compile and link, but you could give it a try. I'm now swamped with other work here at Texas A&M so it's been awhile since I looked at this code. Once again search for //= to find pertinent comments. /* listdiag.cc */ /* * standard header goes here. */ #include extern "C" { #include } #include "wx.h" #include "listdiag.h" ListDialog::ListDialog(wxFrame *parent, int x, int y, char *message, char *caption, int count1, char *list1[], int count2, char *list2[], char **choice, int *index) { if (x < 0) x = 300; if (y < 0) y = 300; wxDialogBox the_dialog(parent, caption, TRUE, x, y, 300, 250); dialog = &the_dialog; dialog->SetClientSize(300, 250); (void)new wxMessage(dialog, message); dialog->NewLine(); listbox = new wxListBox(dialog, NULL, NULL, wxSINGLE, -1, -1, 150, 200, count1, list1); visible_list = 1; c1 = count1; l1 = list1; c2 = count2; l2 = list2; dialog->NewLine(); //= // Here I am setting the callback function of the button to be the // static member function ListDialog::OnOk. The other buttons are // the same way. wxButton *ok = new wxButton(dialog, (wxFunction)ListDialog::OnOk, "OK"); //= // Here is where I set the client data of the button to the this pointer. // This will be used in the static member function to invoke the correct // method on the correct object. ok->SetClientData((char *)this); wxButton *button = new wxButton(dialog, (wxFunction)ListDialog::OnCancel, "Cancel"); button->SetClientData((char *)this); list_select = new wxButton(dialog, (wxFunction)ListDialog::OnListSelect, "Show Inactive"); list_select->SetClientData((char *)this); ok->SetDefault(); dialog->Fit(); dialog->Centre(); dialog->Show(TRUE); *choice = the_selection; *index = the_index; } ListDialog::~ListDialog(void) { return; } void ListDialog::OnOk(wxObject& the_object, wxEvent& the_event) { ListDialog *list_dialog; //= // Here is a static member function which is used as a wxFunction. // The wxObject is the button which was pressed and I use it to get // the client data of the button. Remember the client data is the // this pointer of the object of interest. list_dialog = (ListDialog *)((wxButton&)the_object).GetClientData(); //= // Now that I have the correct object, I can invoke the member function // of the object. list_dialog->OkCallback(); return; } void ListDialog::OnCancel(wxObject& the_object, wxEvent& the_event) { ListDialog *list_dialog; list_dialog = (ListDialog *)((wxButton&)the_object).GetClientData(); list_dialog->CancelCallback(); return; } void ListDialog::OnListSelect(wxObject& the_object, wxEvent& the_event) { ListDialog *list_dialog; list_dialog = (ListDialog *)((wxButton&)the_object).GetClientData(); list_dialog->ListSelectCallback(); return; } void ListDialog::OkCallback(void) { //= // This is the member function of the object which gets invoked from the // static member function ListDialog::OnOk. Now that I'm within a member // function I can access the instance data of the object as well as invoke // other member functions. The other callbacks are handled the same way. the_index = listbox->GetSelection(); if (the_index != -1) { the_selection = copystring(listbox->String(listbox->GetSelection())); } else { the_selection = NULL; } dialog->Show(FALSE); return; } void ListDialog::CancelCallback(void) { the_selection = NULL; the_index = -1; dialog->Show(FALSE); return; } void ListDialog::ListSelectCallback(void) { listbox->Clear(); switch (visible_list) { case 1: listbox->Set(c2, l2); list_select->SetLabel(" Show Active "); visible_list = 2; break; case 2: listbox->Set(c1, l1); list_select->SetLabel("Show Inactive"); visible_list = 1; break; } return; }