From: Stefano Smania MD on 23 Jul 2009 18:07 I've a problem creating custom wxevent for communication from a wxthread and main GUI. I tried with method 4 that you can found on wiky: http://wiki.wxwidgets.org/Custom_Events#Creating_a_Custom_Event_-_Method_4. It works fine if I put all (thread, events, GUI) on a single cpp file. My real problem is to separate the thread in a new separated file. I'm trying but after a month I lost my energy :-) I'm using CB svn 5696 - mingw32 - wxwidgets 2.8.9 on WXP. Wxwidgets example don't use multi files. I've searched on "google code search", but I've not undestood where is the problem. I've 4 files: labMain.cpp , labMain.h , CustomThread.cpp and CustomThread.h . I've removed unnecessary parts: ___________________________________________________ labmain.h #include "CustomThread.h" class labFrame: public wxFrame { public: labFrame(wxWindow* parent,wxWindowID id = -1); virtual ~labFrame(); private: //(*Handlers(labFrame) void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); void OnButton1Click(wxCommandEvent& event); void OnButton2Click(wxCommandEvent& event); //*) //void InterceptEvent( MyCustomEvent &event ); void InterceptEvent( MyCustomEvent & event ); //(*Identifiers(labFrame) static const long ID_BUTTON1; static const long ID_BUTTON2; static const long ID_STATUSBAR1; //*) //(*Declarations(labFrame) wxButton* Button1; wxButton* Button2; wxStatusBar* StatusBar1; //*) DECLARE_EVENT_TABLE() }; #endif // LABMAIN_H ___________________________________________________ labmain.cpp #include "labMain.h" //(*InternalHeaders(labFrame) #include <wx/intl.h> #include <wx/string.h> //*) #include <wx/utils.h> #include <wx/msgdlg.h> //(*IdInit(labFrame) const long labFrame::ID_BUTTON1 = wxNewId(); const long labFrame::ID_BUTTON2 = wxNewId(); const long labFrame::ID_STATUSBAR1 = wxNewId(); //*) MyThread * LocalThread=NULL; // I DEFINE THE THREAD POINTER BEGIN_EVENT_TABLE(labFrame,wxFrame) //(*EventTable(labFrame) //*) END_EVENT_TABLE() DEFINE_EVENT_TYPE( MyCustomCommandEvent ) labFrame::labFrame(wxWindow* parent,wxWindowID id) { //(*Initialize(labFrame) wxGridSizer* GridSizer1; wxBoxSizer* BoxSizer1; Create(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, _T("id")); BoxSizer1 = new wxBoxSizer(wxHORIZONTAL); GridSizer1 = new wxGridSizer(0, 3, 0, 0); Button1 = new wxButton(this, ID_BUTTON1, _("1"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1")); GridSizer1->Add(Button1, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); Button2 = new wxButton(this, ID_BUTTON2, _("2"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON2")); GridSizer1->Add(Button2, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); BoxSizer1->Add(GridSizer1, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); SetSizer(BoxSizer1); StatusBar1 = new wxStatusBar(this, ID_STATUSBAR1, 0, _T("ID_STATUSBAR1")); int __wxStatusBarWidths_1[1] = { -1 }; int __wxStatusBarStyles_1[1] = { wxSB_NORMAL }; StatusBar1->SetFieldsCount(1,__wxStatusBarWidths_1); StatusBar1->SetStatusStyles(1,__wxStatusBarStyles_1); SetStatusBar(StatusBar1); BoxSizer1->Fit(this); BoxSizer1->SetSizeHints(this); Connect(ID_BUTTON1,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&labFrame::OnButton1Click); Connect(ID_BUTTON2,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&labFrame::OnButton2Click); //*) Connect( wxID_ANY, MyCustomCommandEvent,MyCustomEventHandler(labFrame::InterceptEvent), NULL, this ); // I USE CONNECT TO INTERCEPT EVENTS FROM THREAD } labFrame::~labFrame() { //(*Destroy(labFrame) //*) } void labFrame::InterceptEvent( MyCustomEvent &event ) // THIS FUNCTION WILL INTERCEPT EVENTS FROM THREAD { switch( event.GetId() ) { case Custom_DoFirstThing: StatusBar1->SetLabel((wxT("Started thread")+event.GetText())); break; case Custom_DoSecondThing: /* Do something different */ break; // ... } } void labFrame::OnQuit(wxCommandEvent& event) .... void labFrame::OnAbout(wxCommandEvent& event) .... void labFrame::OnButton1Click(wxCommandEvent& event) { if(!LocalThread) { StatusBar1->SetLabel(wxT("Allocating new LocalThread ...")); //wxEvtHandler * EH=GetEventHandler(); LocalThread = new MyThread(GetEventHandler()); // THIS I LINE 139 - I OBTAIN A ERROR HERE } .... } void labFrame::OnButton2Click(wxCommandEvent& event) { .... } ___________________________________________________ CustomThread.h #ifndef CUSTOMTHREAD_H #define CUSTOMTHREAD_H #include <wx/thread.h> #include <wx/event.h> DECLARE_EVENT_TYPE( MyCustomCommandEvent, -1 ) // A custom event that transports a whole wxString. class MyCustomEvent: public wxCommandEvent { public: MyCustomEvent( wxEventType commandType = MyCustomCommandEvent, int id = 0 ) : wxCommandEvent(commandType, id) { } // You *must* copy here the data to be transported MyCustomEvent( const MyCustomEvent &event ) : wxCommandEvent(event) { this->SetText( event.GetText() ); } // Required for sending with wxPostEvent() wxEvent* Clone() const { return new MyCustomEvent(*this); } wxString GetText() const { return m_Text; } void SetText( const wxString& text ) { m_Text = text; } private: wxString m_Text; }; typedef void (wxEvtHandler::*MyCustomEventFunction)(MyCustomEvent &); // This #define simplifies the one below, and makes the syntax less ugly if you want to use Connect() instead of an event table. #define MyCustomEventHandler(func) (wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction) wxStaticCastEvent(MyCustomEventFunction, &func) // Define the event table entry. Yes, it really *does* end in a comma. #define EVT_MYFOO(id, fn) \ DECLARE_EVENT_TABLE_ENTRY( MyCustomCommandEvent, id, wxID_ANY,(wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction) wxStaticCastEvent(MyCustomEventFunction, &fn ), (wxObject*) NULL ), // Optionally, you can do a similar #define for EVT_MYFOO_RANGE. #define EVT_MYFOO_RANGE(id1,id2, fn) DECLARE_EVENT_TABLE_ENTRY( MyCustomCommandEvent, id1, id2, MyCustomEventHandler(fn), (wxObject*) NULL ), // If you want to use the custom event to send more than one sort of data, or to more than one place, make it easier by providing named IDs in an enumeration. enum { Custom_DoFirstThing = 1, Custom_DoSecondThing, Custom_DoThirdThing }; class MyThread : public wxThread { private: protected: public: virtual void* Entry(); //virtual void OnExit(); MyThread(wxEvtHandler *EH); ~MyThread(); wxEvtHandler* ParentH; // I USE IT TO MANTAIN POINTER OF CALLER EVTHANDLER }; #endif ___________________________________________________ CustomThread.cpp #include "CustomThread.h" DEFINE_EVENT_TYPE( MyCustomCommandEvent ) MyThread::MyThread(wxEvtHandler *EH) : wxThread(wxTHREAD_JOINABLE) // CONSTRUCTOR { ParentH=EH; } MyThread::~MyThread() // DESTRUCTOR { } void * MyThread::Entry() { long int pass=0; while(1) { pass++; if (TestDestroy()) break; if(!(pass%10)) { MyCustomEvent event( MyCustomCommandEvent, Custom_DoFirstThing ); wxString bar( wxT("This is a Custom_DoFirstThing event") ); // Add the exciting data. You can put anything you like into the class: ints, structs, binary data... event.SetText( bar ); wxPostEvent( ParentH, event ); // SEND CUSTOM EVENT TO GUI MAIN THREAD } wxThread::Sleep(500); } return(NULL); } ===================================================== When i compile it I obtain: obj\Debug\labMain.o||In function `ZN8labFrame14OnButton1ClickER14wxCommandEvent':| C:\STX\TECNIX\PROGRAMMAZIONE\MULTIPLATFORM\PROGETTI\lab\labMain.cpp | 139 | undefined reference to `MyThread::MyThread(wxEvtHandler*)'| ||=== Build finished: 1 errors, 0 warnings ===| Why "undefined reference"?????? #include "CustomThread.h" is present on labMain.h and codeblock code-completion recognize correctly MyThread. I think that thread is not the problem. I think there is a problem with DEFINE / DECLARE customevent but I don't understand what exactly is wrong. I will appreciate any help you can give me. Thank you. Stefano
From: Smania2000 on 24 Jul 2009 18:38 I resolved myself. 1) Undefined reference is a stupid error on linking files (sorry for it). 2) The real important issue to remember using wxthread and customevents, is that you have to put DECLARE_EVENT_TYPE ( MyCustomCommandEvent, -1 ) only in CustomThread.h and DEFINE_EVENT_TYPE( MyCustomCommandEvent ) in CustomThread.cpp. I hope this example will be usefull for you.
|
Pages: 1 Prev: Idea behind return codes in wxMessageBox? Next: Opening an explorer window |