Share via


Step 5: Adding an Event

Now you will add a ClickIn and a ClickOut event to your ATL control. You will fire the ClickIn event if the user clicks within the polygon and fire ClickOut if the user clicks outside.

When you created the full control in Step 2, you selected the Support Connection Points check box.  This created the IPolyCtlEvents interface in your .idl file.  Note that the interface name starts with an underscore. This is a convention to indicate that the interface is an internal interface. Thus, programs that allow you to browse COM objects can choose not to display the interface to the user. Also notice in the .idl file that Support Connection Points added a line to indicate that IPolyCtlEvents is the default source interface. The source attribute indicates that the control is the source of the notifications, so it will call this interface on the container.

Now you should add the ClickIn and ClickOut methods to the IPolyCtlEvents interface:

  1. Right click on IPolyCtlEvents in ClassView and selecting Add Method… from the popup menu.

  2. Select a Return Type of void.

  3. Type ClickIn in the Method Name box.

  4. Enter [in] long x, [in] long y in the Parameters box.

  5. Click OK.

Check the .idl file to see that the code was added as a method to the IPolyCtlEvents dispinterface.  Then use the same procedure to define a ClickOut method with the same parameters and return type.  The IPolyCtlEvents dispinterface in your .idl file should now look like this:

dispinterface _IPolyCtlEvents
{
   properties:
   methods:
   [id(1), helpstring("method ClickIn")] void ClickIn([in]long x, [in] long y);
   [id(2), helpstring("method ClickOut")] void ClickOut([in] long x, [in] long y);
};

The ClickIn and ClickOut methods that take the x and y coordinates of the clicked point as parameters.

Now generate your type library. To do this you can either rebuild your project or right-click the .idl file in FileView and click Compile Polygon.idl. This will create the Polygon.tlb file, which is your type library.

Next, implement a connection point interface and a connection point container interface for your control. (In COM, events are implemented through the mechanism of connection points. To receive events from a COM object, a container establishes an advisory connection to the connection point that the COM object implements. Since a COM object can have multiple connection points, the COM object also implements a connection point container interface. Through this interface, the container can determine which connection points are supported.) The interface that implements a connection point is called IConnectionPoint and the interface that implements a connection point container is called IConnectionPointContainer.

To help implement IConnectionPoint, use ClassView to access a connection point wizard. This wizard generates the IConnectionPoint interface by reading your type library and implementing a function for each event that can be fired.

To run the wizard, follow these steps:

  1. Go to ClassView (on the View menu, click Workspace to see ClassView).

  2. Right click on your control's implementation class, in this case CPolyCtl.

  3. In the shortcut menu, select Implement Connection Point….

  4. Select _PolyEvents from the Interfaces list then click OK and a proxy class for the connection point will be generated, in this case, CProxy_IPolyCtlEvents.

If you look at the generated PolygonCP.h file in FileView, you see it has a class called CProxy_PolyCtlEvents that derives from IConnectionPointImpl. PolygonCP.h also defines the two methods Fire_ClickIn and Fire_ClickOut, which take the two coordinate parameters. These are the methods you call when you want to fire an event from your control.

The wizard also added the CProxy_PolyEvents and IConnectionPointContainerImpl to your control's multiple inheritance list.  The wizard also exposed IConnectionPointContainer for you by adding appropriate entries to the COM map.

You are finished implementing the code to support events. Now, add some code to fire the events at the appropriate moment. Remember, you are going to fire a ClickIn or ClickOut event when the user clicks the left mouse button in the control. To find out when the user clicks the button, first add a handler for the WM_LBUTTONDOWN message. In ClassView, right click on the CPolyCtl class and select Add Windows Message Handler... from the shortcut menu.  Then select WM_LBUTTONDOWN from the list on the left and click the Add Handler button.  Click OK.

Next, add new code to the OnLButtonDown function in PolyCtl.h (deleting any code placed by the wizard) so that OnLButtonDown now looks like this:

LRESULT CPolyCtl::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
   HRGN hRgn;
   WORD xPos = LOWORD(lParam);  // horizontal position of cursor
   WORD yPos = HIWORD(lParam);  // vertical position of cursor

   CalcPoints(m_rcPos);

   // Create a region from our list of points
   hRgn = CreatePolygonRgn(&m_arrPoint[0], m_nSides, WINDING);

   // If the clicked point is in our polygon then fire the ClickIn
   //  event otherwise we fire the ClickOut event
   if (PtInRegion(hRgn, xPos, yPos))
      Fire_ClickIn(xPos, yPos);
   else
      Fire_ClickOut(xPos, yPos);

   // Delete the region that we created
   DeleteObject(hRgn);
   return 0;
}

Since you have already calculated the points of the polygon in the OnDraw function, use them in OnLButtonDown to create a region. Then, use the PtInRegion API function to determine whether the clicked point is inside the polygon or not.

The uMsg parameter is the ID of the Windows message being handled. This allows you to have one function that handles a range of messages. The wParam and the lParam are the standard values for the message being handled. The parameter bHandled allows you to specify whether the function handled the message or not. By default, the value is set to TRUE to indicate that the function handled the message, but you can set it to FALSE. Doing so will cause ATL to continue looking for another message handler function to which to send the message.

Now try out your events. Build the control and start ActiveX Control Test Container again. This time, view the event log window.  To route events to the output window, select Logging from the Options menu and select Log to output window. Now insert the control and try clicking in the window. Notice that ClickIn is fired if you click within the filled polygon and ClickOut is fired when you click outside of it.

Next you will add a property page.

Back to Step 4On to Step 6