Event Objects
Events are instances of event classes that implement the IEvent interface. The IEvent interface defines the Dispatch() method, which takes a pointer to the object handling the event and invokes the appropriate handler function. Events implement the Dispatch() method by querying the event handler for the appropriate event listener interface and then invoking the handler method on the interface. The relationship between events and event listeners is an example of the visitor design pattern.
Event classes are simply C++ classes that implement the IEvent interface. The Events package implements the most common Windows messages as event classes. Developers can create their own custom event types by implementing the IEvent interface and one or more corresponding event listener types.
Windows Messages
A Windows message is a type of event generated by the operating system and queued up for an application. The Windows Platform SDK defines constants using the naming convention WM_XXX for messages. The Events package defines the IWinEvent interface, which provides methods for accessing the message ID, WPARAM, LPARAM, and result value of a Windows message. All Window events implement the IWinEvent interface. The CWinEvent template class makes it easy to implement new Windows event classes by providing a default implementation of the IWinEvent interface.
Example 31 shows how the
WM_PAINT message is implemented using the
CWinEvent class. First, an interface is derived from
IWinEvent that defines a method for cracking the
WM_PAINT message.
Example 31 – Implementing the WM_PAINT message by using the CWinEvent class
class __declspec(uuid("8A6AF181-40A7-11d3-AF0D-006008AFE059"))
IWindowPaintEvent : public IWinEvent
{
public:
virtual HDC GetDC() const = 0;
};
Next, the class
CWindowPaintEvent is derived from the
CWinEventBase class, as shown in
Example 32. The template parameters for
CWinEventBase are the interface for the event and the GUID for that interface. The
CWindowPaintEvent class implements the
Dispatch() method inherited from
IEvent and the
GetDC() method inherited from
IWindowPaintEvent.
Example 32 – Deriving CWindowPaintEvent from the CWinEventBase class
class CWindowPaintEvent : public CWinEventBase<IWindowPaintEvent,
&IID_IWindowPaintEvent>
{
…
virtual bool Dispatch(IQueryGuid* pIListener);
virtual HDC GetDC() const;
…
};
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;
}
HDC CWindowPaintEvent::GetDC() const
{
return (HDC) GetWParam();
}
The Event Factory
The
CEventFactory class translates Windows messages into event objects. It contains a method named
CreateWindowsEvent(), which takes a message
ID,
WPARAM, and
LPARAM and creates the appropriate type of Windows event object. The
CEventFactory class defines a virtual
FilterWindowsEvent() method to provide derived classes the opportunity to filter events. Command messages are handled by the
CreateCommandEvent() and
FilterCommandEvent() methods.
Example 33 shows the definition of the
CEventFactory class.
Example 33 – CEventFactory class definition
class CEventFactory
{
public:
virtual bool FilterWindowsEvent(UINT message, WPARAM wParam,
LPARAM lParam);
virtual IEvent* CreateWindowsEvent(UINT message, WPARAM wParam,
LPARAM lParam);
virtual bool FilterCommandEvent(UINT nID, int nCode);
virtual IEvent* CreateCommandEvent(UINT nID, int nCode);
virtual IEvent* CreateCommandQueryEvent(UINT nID);
};
Windows Message Cracking
Message cracking is a natural by-product of encapsulating the
WPARAM and
LPARAM of a Windows event in an object. Calling member functions to crack a Windows message is more convenient and type-safe than using macros.
Example 34 illustrates a window procedure that cracks mouse events and saves the point at which the mouse event occurred.
Example 34 – Windows procedure that cracks mouse events and saves the event point
static POINT g_ptLast;
LRESULT WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
static CEventFactory factory;
IEvent* pEvent = factory.CreateWindowsEvent(nMsg, wParam, lParam);
IMouseEvent* pMouseEvent = guid_cast<IMouseEvent*>(pEvent);
if (pMouseEvent != NULL)
{
pMouseEvent->GetPoint(g_ptLast);
}
. . .
}