Custom Event Topic is solved

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
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Custom Event

Post by mspoerr »

Hello,

since my problems with threads and events (http://forums.wxwidgets.org/viewtopic.php?t=24663) I am fighting with custom events.
I combined the example from the above topic with this one:
http://wiki.wxwidgets.org/Custom_Events ... -_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?

Thanks,
mspoerr

Custom Event Code:

Code: Select all

#ifndef __LOGEVENT__
#define __LOGEVENT__

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

DECLARE_EVENT_TYPE( EVT_LOG_MELDUNG, -1 )

class LogEvent: public wxEvent
{
	boost::any data;

public:
	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)                                         \
	(wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction)\
	wxStaticCastEvent(LogEventFunction, &func)                    

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

#endif
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);
		evt.SetData(&evtDat);
		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);
	}	
}
DavidHart
Site Admin
Site Admin
Posts: 4252
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post by DavidHart »

Hi,

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.

Regards,

David
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Post by mspoerr »

Hi,

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

Thanks,
mspoerr
DavidHart
Site Admin
Site Admin
Posts: 4252
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post 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.
Frank
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Jan 01, 2005 6:19 pm

Post 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(v.data) { }
But as I said, this is exacley what the compiler creates for you anyway...
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Post by mspoerr »

I now added

Code: Select all

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

Thanks,
mspoerr

EDIT: I just saw the new posts. I will try and come back.
mspoerr
Experienced Solver
Experienced Solver
Posts: 50
Joined: Sat Mar 15, 2008 9:17 pm

Post by mspoerr »

Frank, it now works the suggested changes. Thank you very much for your help!

/mspoerr
Post Reply