The ActiveX Control Interface Wizard lets you base new controls on
existing controls. The code generated by the wizard can be difficult to
understand, however, so this section shows you how to create an ActiveX control
manually. Once you understand the parts of an ActiveX control, it's easier to use
the ActiveX Control Interface Wizard.
ActiveX Control Design Steps
To create an ActiveX control, follow these steps:
Create a new ActiveX control project.
The following text discusses the first six steps in greater detail while
providing instructions on how to build a sample control named Blinker
(BLINKER.VBP). The Blinker control is used to flash controls or windows on screen for emphasis. Debugging and compiling the control are discussed in the two sections that follow, "Dear John, How Do I... Debug a Control?" and "Dear John, How Do I... Compile and Register a Control?"
Creating the ActiveX Control Project
To create an ActiveX Control project, follow these steps:
The Blinker control flashes other controls or windows in your application in order to draw the user's attention. This isn't spectacularly hard to dowhich is one reason it makes a good sample. The Blinker control uses an ActiveX UpDown control, an intrinsic TextBox control, and an intrinsic Timer control, as shown in Figure 6-1.
Figure 6-1. The visual interface of the Blinker control, which contains one ActiveX control and two intrinsic controls.
To create the visual interface of the Blinker control, follow these steps:
You can be sloppy when drawing the Blinker interface because the size and position of the visible controls must be handled in code anyway. When users draw the Blinker control on a form, they can click and drag the control to make it the size they want. Resizing triggers the UserControl_Resize event procedure, which positions and sizes the visible interface of the control appropriately.
The following code handles resizing the Blinker control:
`Code for control's visual interface
Private Sub UserControl_Resize()
`Be sure visible controls are
`positioned correctly within the
`UserControl window
updnRate.Top = 0
txtRate.Top = 0
txtRate.Left = 0
`Resize visible controls
`when user control is resized
updnRate.Height = Height
txtRate.Height = Height
`Adjust UpDown control's width up
`to a maximum of 240 twips
If Width > 480 Then
updnRate.Width = 240
Else
updnRate.Width = Width \ 2
End If
`Set width of text box
txtRate.Width = Width - updnRate.Width
`Move UpDown control to right edge of
`text box
updnRate.Left = txtRate.Width
End Sub
As you can see, I got a little fancy with the resize code for the
UpDown control. Rather than fix it at 240 twips, I let it scale down if the user makes the Blinker control less than 480 twips. Your resize code can be as simple or as complicated as you want.
Adding Properties, Methods, and Events
In addition to the standard size, position, and visibility properties provided with all controls, the Blinker control has a TargetObject property, which specifies the object that will blink, and an Interval property, which specifies how many times per second the object should blink. The Blinker control also includes a Blinked event, which occurs after the object blinks, and a Blink method, which sets the TargetObject and Interval properties.
ActiveX control properties, methods, and events are defined in the same way as class properties, methods, and events. The following code shows the TargetObject, Interval, Blinked, and Blink members of the control:
Option Explicit
`Windows API to flash a window
Private Declare Function FlashWindow _
Lib "user32" ( _
ByVal hwnd As Long, _
ByVal bInvert As Long _
) As Long
`Blinked event definition
Public Event Blinked()
`Internal variables
Private mobjTarget As Object
Private mlngForeground As Long
Private mlngBackground As Long
Private mblnInitialized As Boolean
`Public error constants
Public Enum BlinkerErrors
blkCantBlink = 4001
blkObjNotFound = 4002
End Enum
`Code for control's properties and methods
`~~~.TargetObject
Public Property Set TargetObject(Setting As Object)
If TypeName(Setting) = "Nothing" Then Exit Property
`Set internal object variable
Set mobjTarget = Setting
End Property
Public Property Get TargetObject() As Object
Set TargetObject = mobjTarget
End Property
`~~~.Interval
Public Property Let Interval(Setting As Integer)
`Set UpDown control--updates TextBox and
`Timer controls as well
updnRate.Value = Setting
End Property
Public Property Get Interval() As Integer
Interval = updnRate.Value
End Property
`~~~.Blink
Sub Blink(TargetObject As Object, Interval As Integer)
`Delegate to TargetObject and Interval properties
Set Me.TargetObject = TargetObject
Me.Interval = Interval
End Sub
The TargetObject Property Set procedure sets the target object that
should blink by assigning an internal object variable. The Interval property merely sets or returns the value of the UpDown
controlthis changes the value in the text box and thereby changes the Timer control's Interval property. The
Blinked event is defined here but is triggered from the Timer event. Next I'll show you the event procedures for the UpDown, Timer, and TextBox
controlswhere the real work is done.
Programming the Control's Behavior
So far, the Blinker control looks nice, but doesn't do anything. The control's behaviorflashing a control or windowis determined by code in the UpDown control's Change event procedure, the timer's Timer event procedure, and the text box's Change event procedure, as shown here:
`Code for control's behavior
Private Sub updnRate_Change()
`Update the text box control
txtRate.Text = updnRate.Value
End Sub
Private Sub tmrBlink_Timer()
On Error GoTo errTimer
`Counter to alternate blink
Static blnOdd As Boolean
blnOdd = Not blnOdd
`If the object is a form, use FlashWindow API
If TypeOf mobjTarget Is Form Then
FlashWindow mobjTarget.hwnd, CLng(blnOdd)
`If it's a control, swap the colors
ElseIf TypeOf mobjTarget Is Control Then
If Not mblnInitialized Then
mlngForeground = mobjTarget.ForeColor
mlngBackground = mobjTarget.BackColor
mblnInitialized = True
End If
If blnOdd Then
mobjTarget.ForeColor = mlngBackground
mobjTarget.BackColor = mlngForeground
Else
mobjTarget.ForeColor = mlngForeground
mobjTarget.BackColor = mlngBackground
End If
Else
Set mobjTarget = Nothing
GoTo errTimer
End If
`Trigger the Blinked event
RaiseEvent Blinked
Exit Sub
errTimer:
If TypeName(mobjTarget) = "Nothing" Then
Err.Raise blkObjNotFound, "Blinker control", _
"Target object is not valid for use with this control."
Else
Err.Raise blkCantBlink, "Blinker control", _
"Object can't blink."
End If
End Sub
Private Sub txtRate_Change()
`Set Timer control's Interval property
`to match value in text box
If txtRate = 0 Then
tmrBlink.Interval = 0
tmrBlink.Enabled = False
mblnInitialized = False
`If blinking is turned off, be sure object
`is returned to its original state
If TypeOf mobjTarget Is Form Then
FlashWindow mobjTarget.hwnd, CLng(False)
ElseIf TypeOf mobjTarget Is Control Then
mobjTarget.ForeColor = mlngForeground
mobjTarget.BackColor = mlngBackground
End If
Else
tmrBlink.Enabled = True
tmrBlink.Interval = 1000 \ txtRate
End If
End Sub
The UpDown control's Change event procedure simply copies the value of the UpDown control to the text box. The timer's Timer event procedure handles the flashing by using the FlashWindow API function for forms or by swapping the ForeColor and BackColor properties for visible controls. Using the FlashWindow API function is more effective than swapping the ForeColor and BackColor properties. The text box's Change event procedure handles the blinking rate.
SEE ALSO
- Chapter 12, "Dialog Boxes, Windows, and Other Forms," for more information about the FlashWindow API function