From: Stefano Smania MD on
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
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.