65.9K
CodeProject is changing. Read more.
Home

Simple Events System

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (6 votes)

Nov 27, 2002

1 min read

viewsIcon

70616

downloadIcon

1784

This code is based on Jeffry Ritcher "Applicate .NET Framework"

Introduction

Microsoft introduced an events system in VC++ 7 using keywords (event_source, event_receiver, __event, __raise, __hook, __unhook), expanding the language with a great tool. This cool feature is not provided in VC++ 6.0 language.

My code provides users of VC++ 6.0 (could be used in other C++ systems) a simple events system, made in VC++ 6.0 and STL, with a small amount of code needed in order to use it.

Using the code

The first thing to do is define the events provider, the events list and a struct that contains the events arguments.

The code is something like this:

1. Defining the events argument's list struct (inherited from EventArgs).

//**** Source Event Arguments
struct SourceEventArgs : EventArgs {
	// Only have a int argument, but the 
	// structure could be more complex
	int nRetCode;
	// ... Others arguments needed for any Source class event 
};

2. Declaring a class capable of "firing" the events (inherited from SourceEvents).

// Generate events
class Source : public SourceEvents {
	...
};

3. Construct the "events" map

// Generate events
class Source : public SourceEvents {
protected:
	//Events provided for this class
	_BEGIN_EVENTS_HANDLER
		_EVENT_HANDLER( Close )
		_EVENT_HANDLER( Idle  )
	_END_EVENTS_HANDLER
	...

4. Define methods to "fire" the events

// Generate events
class Source : public SourceEvents {
protected:
	//Events provided for this class
	_BEGIN_EVENTS_HANDLER
		_EVENT_HANDLER( Close )
		_EVENT_HANDLER( Idle  )
	_END_EVENTS_HANDLER

   // Any name is acceptable but the standar is OnEventName
	void OnIdle();

   // this is a normal method that is calling for your code
   // so any signature is correct ( Ex. int OnClose(int) ).
   int OnClose(int);	
			

	...

//Implementation file
void Source::OnIdle() { 
	//_raise 
	SourceEventArgs e;
	e.nRetCode = 0;
	_raise(Idle, &e); // <-- this is the event launch
}

int Source::OnClose(int nRetCode) { 
	//_raise 
	SourceEventArgs e;
	e.nRetCode = nRetCode;
	_raise(Idle, &e); // <-- this is the event launch
	return e.nRetCode;
}

Ok, now the we have the class Source, it can launch Close and Idle events for any number of event listener. And now we need a class capable of listening to the events generated.

The code is simple

// Events Listener
class Target {
	int m_code;
public:
	Target(int i) : m_code(i) { }
	//A normal way for declare this function is under protected and
	//call this internally when the event have to be generated.
	//Use the source object is not necesary but can help you
	//for do some task.
	void OnIdle(Source* pObj, SourceEventArgs* e) {
		cout << "Target" << m_code <<
                                " el valor actual de e = " << e->nRetCode++;
		cout << " " << pObj->Name() << endl;
	}
	// Return event value is allowed by use of structure
	void OnClose(Source* /*pObj*/, SourceEventArgs* e) {
		cout << "Target" << m_code <<
                                 " el valor actual de e = "<< e->nRetCode << endl;
		e->nRetCode = 4;
	}

	// Subscription function (Source is the class name for events
	//generator class).
	_DECLARE_HOOK_LIST( Source ) // <-- this is the declaration of listener.
};

// implementation file
// this define the hooks for each events catch for this class
// Source class name of events generator
// Target class name of events listener
// SourceEventArgs struct name of events arguments struct
_BEGIN_HOOK_LIST(Source, Target, SourceEventArgs)
	_HOOK(Idle , OnIdle ) // Idle the name of event
	_HOOK(Close, OnClose) // OnIdle the name of function how process the event
_END_HOOK_LIST

The last step is joining the object to listening events.

// Creating objects
Source s;
Target t(1);

// Joining listener for listening (t) events generated by Sourcer (s)
t.JoinTo(&s);

// launch events directly you may call this methods internally.
s.Idle();
s.Close();

//UnJoin
t.UnJoinTo(&s); // can use t.JoinTo(&s, false);

Remember that it is important to call the unjoin method before erasing the objects

Comment

Ok this it's my first one article and I expect that be of great aid. Please let me know and good look.

Edit History

27 Nov 2002 - Initial Edit

3 Dec 2002 - updated downloads