Dispatching Events

Notice that the event listener passes a pointer to itself into the event object’s Dispatch() method. The Dispatch() method queries the listener for an interface that it understands and then invokes the callback method on that interface. Invoking the OnPaint() callback function demonstrates how the paint event class invokes the OnPaint() callback function.

Invoking the OnPaint() callback function

bool CWindowPaintEvent::Dispatch(IQueryGuid* pIListener)

{

bool bHandled = false;

IWindowListener* pIWindowListener =

guid_cast<IWindowListener*>(pIListener);

 

if (pIWindowListener != NULL)

{

bHandled = pIWindowListener->OnPaint(GetDC());

pIWindowListener->Release();

}

 

return bHandled;

}

The event’s Dispatch() method checks to see if it has the right type of listener. If it does have the right listener, it invokes the appropriate callback method. In the preceding sample code, the event listener is expected to implement the IWindowListener interface to receive the OnPaint() callback.

Although HandleEvent() method is sufficient for handling all the events that a listener is interested in receiving, doing so would be equivalent to writing a window procedure containing a big switch() statement. The idea behind making event handling simpler is to map events onto individual member functions. For example, you could map a WM_PAINT message onto an OnPaint() member function that receives a device context as a parameter. Event listener interfaces extend the base IEventListener interface with callback functions that are invoked to handle events. An example of an event listener interface is IWindowListener, shown in An event listener interface, IWindowListener.

An event listener interface, IWindowListener

class __declspec(uuid("A67C846D-0A0A-4b5e-8DC0-3DA18454F582"))

IWindowListener : public IEventListener

{

public:

virtual bool OnCreate(LPCREATESTRUCT lpCreateStruct) = 0;

virtual bool OnDestroy() = 0;

virtual bool OnMove(int x, int y) = 0;

virtual bool OnSize(UINT nFlag, int cx, int cy) = 0;

virtual bool OnEraseBkgnd(HDC hDC) = 0;

virtual bool OnPaint(HDC hDC) = 0;

virtual bool OnWindowPosChanging(LPWINDOWPOS lpWindowPos) = 0;

virtual bool OnWindowPosChanged(LPWINDOWPOS lpWindowPos) = 0;

virtual bool OnTimer(UINT nIDTimer) = 0;

};

The HandleEvent() method inherited from IEventListener is called to handle all events, but it delegates the work to the callback functions by calling the event object’s Dispatch() method. The flow of control for handling events is as follows:

 

Event object->HandleEvent->Dispatch->Callback function

The event object is passed to the event listener’s HandleEvent() method. The HandleEvent() method delegates the task of invoking the correct callback function to the event object. Be aware that this is only the default behavior, and can easily be overridden. For example, you might handle certain events directly in your event listener’s HandleEvent() method without invoking a callback function. It is also possible to implement HandleEvent() in such a way that it bypasses the event object’s Dispatch() method and invokes the callback methods directly. The architecture is flexible enough to allow many different event listener implementations.