Page 1 of 1

Custom Event

Posted: Fri Jul 03, 2009 5:15 pm
by mspoerr

since my problems with threads and events ( I am fighting with custom events.
I combined the example from the above topic with this one: ... -_Method_4

I want to send a struct from one thread to another one, but when processing the sent data, it is invalid.
Sending the event itself works. Sending a only a string also works.

Whats wrong?


Custom Event Code:

Code: Select all

#ifndef __LOGEVENT__
#define __LOGEVENT__

#include <boost/any.hpp>
#include <wx/event.h>


class LogEvent: public wxEvent
	boost::any data;

	LogEvent () : wxEvent(0, EVT_LOG_MELDUNG) { }
	LogEvent (const boost::any& data) : wxEvent(0, EVT_LOG_MELDUNG), data(data) {  }
	~LogEvent () { }

	wxEvent* Clone () const { return new LogEvent(*this); }

	void SetData (const boost::any& data) { this->data = data; }
	boost::any GetData () const { return data; }

	template<typename T> T GetData () const { return boost::any_cast<T>(data); }


typedef void (wxEvtHandler::*LogEventFunction)(LogEvent &);

#define LogEventHandler(func)                                         \
	wxStaticCastEvent(LogEventFunction, &func)                    

// Define the event table entry. Yes, it really *does* end in a comma.
#define EVT_LOG(id, fn)                                            \
	(wxObjectEventFunction)(wxEventFunction)                     \
	(wxCommandEventFunction) wxStaticCastEvent(                  \
	LogEventFunction, &fn ), (wxObject*) NULL ),

Sendig the event:

Code: Select all

void Ersetzer::schreibeLog(int type, string logEintrag, int farbe, int format, int groesse)
	if (logAusgabe != NULL)
		WkLog::evtData evtDat;
		evtDat.farbe = farbe;
		evtDat.format = format;
		evtDat.groesse = groesse;
		evtDat.logEintrag = logEintrag;
		evtDat.type = type;
		LogEvent evt(EVT_LOG_MELDUNG);
		wxPostEvent(logAusgabe, evt);
Receive the event:

Code: Select all

void WkLog::OnSchreibeLog1(LogEvent &event)
	boost::any data = event.GetData();
	if (data.type() == typeid(evtData*))
		evtData *evtDat = event.GetData<evtData*>();
		schreibeLog(evtDat->type, evtDat->logEintrag, evtDat->farbe, evtDat->format, evtDat->groesse);

Posted: Fri Jul 03, 2009 5:31 pm
by DavidHart

LogEvent doesn't have a copy ctor defined, which means that the Clone() method won't work properly. And wxPostEvent uses Clone() to make a copy of evt, then sends the copy.

All of which means that the data won't be available in WkLog::OnSchreibeLog1.



Posted: Fri Jul 03, 2009 5:35 pm
by mspoerr

thank you for the answer. How should this "copy ctor" look like?


Posted: Fri Jul 03, 2009 6:47 pm
by DavidHart
Much the same as the one in Method 4, which is
MyFooEvent( const MyFooEvent &event )
: wxCommandEvent(event) { this->SetText( event.GetText() ); }

except that your base-class is wxEvent, not wxCommandEvent; and you will use LogEvent::SetData and LogEvent::GetData instead of S/GetText.

Posted: Fri Jul 03, 2009 7:32 pm
by Frank
You don't need a Copyconstructor. The Default Copy-Ctor, wich the compiler creates for you, calls the Copy-Ctor for everey Member.

The Copy-CTor for boost::any does just fine.

No need to implement your own.

Your problem is, you posting a pointer to a local object. After your function ends, this pointer points into nirvana, you crash. Always keep in mind, posting an event just puts it in the message queue. It does not wait for the other side to get the event (that would be SendEvent, wich is sadly not supportet by wx). This means, you have to be sure, your data lives until the Event gets popped from the message queue.

Use a Copy instead of a pointer an you should be fine:

Code: Select all

LogEvent evt(EVT_LOG_MELDUNG);
evt.SetData(evtDat);  // <--- Copy
wxPostEvent(logAusgabe, evt);
The same of couse for the receiving side. Just ommit the asterisk: evtData evtDat = event.GetData<evtData>();

The alternative: create your struct on the heap (new evtData) an post a pointer to that. That way, you can be sure, the obect still exists when your function ends (and thus when the event is received). Remember to delete the object in your eventhandler.

Edit: Oh, if you absoluteley wan't to create a copy-ctor, it should look like this:
LogEvent(const LogEvent& v) : data( { }
But as I said, this is exacley what the compiler creates for you anyway...

Posted: Fri Jul 03, 2009 7:45 pm
by mspoerr
I now added

Code: Select all

LogEvent( const LogEvent &event )
		:  wxEvent(event) { this->SetData( event.GetData() ); }
but it still doesn't work...


EDIT: I just saw the new posts. I will try and come back.

Posted: Fri Jul 03, 2009 8:55 pm
by mspoerr
Frank, it now works the suggested changes. Thank you very much for your help!