previous page
next page

The BullsEye Control Requirements

This chapter describes the ATL implementation of a feature-rich control called BullsEye. The BullsEye control implements all the previously described features. The BullsEye control draws a bull's eye. You can configure the number of rings in the bull's eye (from one to nine) and the color of the center ring, as well as the color of the ring adjacent to the center (called the alternate ring color). BullsEye draws additional rings by alternately using the center and alternate colors.

The area around the bull's eye can be transparent or opaque. When transparent, the background around the bull's eye shows through. When opaque, the bull's eye fills the area around the circle using the background color. By default, BullsEye uses the container's ambient background color as the background color. BullsEye also uses the foreground color to draw a line separating each ring

You can assign score values to each ring. By default, the center ring is worth 512 points and each other ring is worth half the points of its adjacent inner ring. When a user clicks on a ring, the control fires an OnRingHit event and an OnScoreChanged event. The argument to the OnRingHit event method specifies the ring upon which the user clicked. Rings are numbered from 1 to N, where 1 is the centermost ring. The OnScoreChanged event specifies the point value of the clicked ring. For example, clicking on ring 2 with default scores fires an OnScoreChanged event with an argument of 256 points.

In addition, when you click on one of the bull's-eye rings, the control can provide feedback by playing a sound. By default, you hear the sound of an arrow striking the bull's eye. The Boolean Beep property, when set to trUE, indicates that the control should play its sound on a ring hit.

BullsEye supports all standard control functionality. In addition to windowed activation, BullsEye can be activated as a windowless control when its container supports such functionality.

Many containers ask their controls to save their state using the IPersistStreamInit interface and an IStream medium. When embedding a control in an OLE document, a container asks a control to save its state using the IPersistStorage interface and the IStorage medium. A container, such as Internet Explorer and Visual Basic, that prefers to save the state of a control as textual name/value pairs uses the control's IPersistPropertyBag interface and the IPropertyBag medium. BullsEye supports all three persistence protocols and mediastreams, storages, and property bags.

BullsEye also provides two property pages. One property page is custom to the BullsEye control and enables you to set the Enabled, Beep (sound on ring hit), and BackStyle (TRansparent) properties (see Figure 11.1).

Figure 11.1. BullsEye custom property page


The other property page is the standard color-selection property page (see Figure 11.2). The BullsEye control has four color properties: the center ring color, the alternate ring color, the background color (used to fill the area around the bull's eye) and the foreground color (used to draw the separator line between rings).

Figure 11.2. BullsEye color property page


The BullsEye control also categorizes its properties for Visual Basic 6. VB6 has a property-view window in which you can select a view that sorts the properties by standard and control-defined categories (see Figure 11.3).

Figure 11.3. Visual Basic 6 property view window for BullsEye


The BullsEye control lists its color properties and the RingCount property in the standard Appearance category. The control lists its Beep property in the standard Behavior category.

BullsEye also supports per-property browsing, which allows a control to specify a list of strings that a container should display as the available choices for a property's value. Notice in the example Visual Basic property view window that, in the Behavior category, Visual Basic displays the strings "Yes, make noise" and "No, be mute" as the selections available for the Beep property.

Also notice that the Misc category contains an entry called (About) that represents the AboutBox stock method. BullsEye displays the dialog box shown in Figure 11.4 when the user selects the About entry.

Figure 11.4. BullsEye About box


Requirements: The Properties and Methods

BullsEye supports the four stock properties shown in Table 11.1.

Table 11.1. BullsEye Stock Properties

Property Name

Type

Stock DISPID

Description

BackColor

OLE_COLOR

DISPID_BACKCOLOR

Background color

BackStyle

Long

DISPID_BACKSTYLE

Background style, transparent or opaque

Enabled

VARIANT_BOOL

DISPID_ENABLED

Enabled status, trUE or FALSE

ForeColor

OLE_COLOR

DISPID_FORECOLOR

Foreground color


In addition, BullsEye supports all three stock methods, as shown in Table 11.2.

Table 11.2. BullsEye Stock Methods

Method Name

Stock DISPID

Description

AboutBox

DISPID_ABOUTBOX

Displays the control's Help About dialog box

DoClick

DISPID_DOCLICK

Simulates a mouse click on the control

Refresh

DISPID_REFRESH

Redraws the control


Finally, BullsEye supports the custom properties listed in Table 11.3.

Table 11.3. BullsEye Custom Properties

Property Name

Type

Custom DISPID

Description

Application

IDispatch*

DISPID_APPLICATION

Returns the IDispatch* for the hosting application

AlternateColor

OLE_COLOR

DISPID_ALTERNATECOLOR

Gets/sets the color of the alternate (even) rings

Beep

VARIANT_BOOL

DISPID_BEEP

Enables/disables sound effects for the control

CenterColor

OLE_COLOR

DISPID_CENTERCOLOR

Gets/sets the color of the center (odd) rings

Parent

IDispatch*

DISPID_PARENT

Returns the IDispatch* for the control's parent

RingCount

Short

DISPID_RINGCOUNT

Gets/sets the number of rings

RingValue

Long

DISPID_RINGVALUE

Gets/sets the value of each ring


Declaring the Properties and Methods in IDL

A control container accesses the properties and methods of a control using the control's IDispatch interface. A control must therefore provide an implementation of IDispatch when it has properties and methods.

ATL-based controls in generaland the BullsEye control, specificallyimplement their properties and methods using a dual interface, not a dispatch interface, even though a dual interface is unnecessary because the vtable portion of the dual interface typically goes unused. A custom C++ control container can access the control's properties and methods using the vtable, but no other container currently does. Visual Basic 6 accesses properties and methods of a control using the control's IDispatch interface. Visual Basic uses the vtable portion of a dual interface only for noncontrol objects.

The BullsEye control provides access to its properties and methods on the default IBullsEye dual interface. When you generate a new ATL-based control class, the wizard generates the definition of the default dual interface, but you must populate the definition with the accessor methods for your control's properties and the control's methods. Listing 11.1 gives the definition of the IBullsEye interface.

Listing 11.1. The IBullsEye Interface
[ object,
  uuid(B4FBD008-B03D-4F48-9C5B-4A981EB6A515),
  dual, nonextensible, helpstring("IBullsEye Interface"),
  pointer_default(unique)
]
interface IBullsEye : IDispatch {
    const int DISPID_ALTERNATECOLOR = 1;
    const int DISPID_BEEP = 2;
    const int DISPID_CENTERCOLOR = 3;
    const int DISPID_RINGCOUNT = 4;
    const int DISPID_RINGVALUE = 5;
    const int DISPID_APPLICATION = 6;
    const int DISPID_PARENT = 7;

    // Stock Properties
    [propput, bindable, requestedit, id(DISPID_BACKCOLOR)]
    HRESULT BackColor([in]OLE_COLOR clr);
    [propget, bindable, requestedit, id(DISPID_BACKCOLOR)]
    HRESULT BackColor([out,retval]OLE_COLOR* pclr);
    [propput, bindable, requestedit, id(DISPID_BACKSTYLE)]
    HRESULT BackStyle([in]long style);
    [propget, bindable, requestedit, id(DISPID_BACKSTYLE)]
    HRESULT BackStyle([out,retval]long* pstyle);
    [propput, bindable, requestedit, id(DISPID_FORECOLOR)]
    HRESULT ForeColor([in]OLE_COLOR clr);
    [propget, bindable, requestedit, id(DISPID_FORECOLOR)]
    HRESULT ForeColor([out,retval]OLE_COLOR* pclr);
    [propput, bindable, requestedit, id(DISPID_ENABLED)]
    HRESULT Enabled([in]VARIANT_BOOL vbool);
    [propget, bindable, requestedit, id(DISPID_ENABLED)]
    HRESULT Enabled([out,retval]VARIANT_BOOL* pbool);

// Stock methods
    [id(DISPID_ABOUTBOX)] HRESULT AboutBox( );
    [id(DISPID_DOCLICK)] HRESULT DoClick( );
    [id(DISPID_REFRESH)] HRESULT Refresh( );
    // Custom properties
    [propget, bindable, requestedit, id(DISPID_APPLICATION)]
    HRESULT Application([out, retval] IDispatch** pVal);

    [propget, bindable, requestedit, id(DISPID_ALTERNATECOLOR)]
    HRESULT AlternateColor([out, retval] OLE_COLOR* pVal);
    [propput, bindable, requestedit, id(DISPID_ALTERNATECOLOR)]
    HRESULT AlternateColor([in] OLE_COLOR newVal);

    [propget, bindable, requestedit, id(DISPID_BEEP)]
    HRESULT Beep([out, retval] VARIANT_BOOL* pVal);
    [propput, bindable, requestedit, id(DISPID_BEEP)]
    HRESULT Beep([in] VARIANT_BOOL newVal);

    [propget, bindable, requestedit, id(DISPID_CENTERCOLOR)]
    HRESULT CenterColor([out, retval] OLE_COLOR* pVal);
    [propput, bindable, requestedit, id(DISPID_CENTERCOLOR)]
    HRESULT CenterColor([in] OLE_COLOR newVal);

    [propget, bindable, requestedit, id(DISPID_PARENT)]
    HRESULT Parent([out, retval] IDispatch** pVal);

    [propget, bindable, requestedit, id(DISPID_RINGCOUNT)]
    HRESULT RingCount([out, retval] SHORT* pVal);
    [propput, bindable, requestedit, id(DISPID_RINGCOUNT)]
    HRESULT RingCount([in] SHORT newVal);

    [propget, bindable, requestedit, id(DISPID_RINGVALUE)]
    HRESULT RingValue([in] SHORT sRingNumber,
        [out, retval] LONG* pVal);
    [propput, bindable, requestedit, id(DISPID_RINGVALUE)]
    HRESULT RingValue([in] SHORT sRingNumber, [in] LONG newVal);
};

Requirements: The Events

BullsEye Custom Events

The BullsEye control doesn't support any of the stock events. However, it has two custom events, as detailed in Table 11.4.

Table 11.4. BullsEye Custom Events

Event

Event DISPID

Description

void OnRingHit (short sRingNumber)

DISPID_ONRINGHIT

The user clicked on one of the bull's-eye rings. The argument specifies the ring that the user clicked. Rings are numbers from 1 to N from the center outward.

void OnScoreChanged (long RingValue)

DISPID_ONSCORECHANGED

This event follows the OnRingHit event when the user clicks on a bull's-eye ring. The argument specifies the score value of the ring that the user clicked.


An event interface contains only methods and should be a dispatch interface for all containers to receive the event callbacks. Some containers, such as Visual Basic, can receive event callbacks on custom IUnknown-derived interfaces. An event interface should never be a dual interface.

Declaring the Event Dispatch Interface in IDL

Listing 11.2 gives the definition of the _IBullsEyeEvents dispatch interface. For the constants for the DISPIDs to appear in the MIDL-generated C/C++ header file, the definitions of the constants must appear in the IDL file outside of the library block. You must define the dispinterface itself inside the library block.

Listing 11.2. The _IBullsEyeEvents Dispatch Interface
const int DISPID_ONRINGHIT      = 1;
const int DISPID_ONSCORECHANGED = 2;

[ uuid(58D6D8CB-765D-4C59-A41F-BBA8C40F7A14),
  helpstring("Event interface for BullsEye Control")
]
dispinterface _IBullsEyeEvents {
    properties:
    methods:
    [id(DISPID_ONRINGHIT)]
    void OnRingHit(short ringNumber);
    [id(DISPID_ONSCORECHANGED)]
    void OnScoreChanged(long ringValue);
};

Requirements: The BullsEye and Property Page Coclasses

You must also define the BullsEye coclass in the library block of the IDL file (see Listing 11.3). At a minimum, you must specify the default IDispatch interface (IBullsEye) via which a container can access the control's properties and methods, and the default source interface (_IBullsEyeEvents) tHRough which the BullsEye control fires events to its container.

Listing 11.3. The BullsEye Coclass
[   uuid(E9312AF5-1C11-4BA4-A0C6-CB660E949B78),
    control, helpstring("BullsEye Class")
]
coclass BullsEye {
    [default] interface IBullsEye;
    [default, source] dispinterface _IBullsEyeEvents;
};

Additionally, you should define all the custom property page classes implemented by your control in the library block of the IDL file. BullsEye has only one custom property page, called BullsEyePropPage (see Listing 11.4).

Listing 11.4. The BullsEyePropPage Coclass
[   uuid(47446235-8500-43a2-92A7-F0686FDAA69C),
    helpstring("BullsEye Property Page class")
]
coclass BullsEyePropPage {
    interface IUnknown;
};


previous page
next page
Converted from CHM to HTML with chm2web Pro 2.75 (unicode)