The previous two chapters have demonstrated how to create ActiveX controls from other controls. In Chapter 24, "Creating ActiveX Controls," you saw how to combine standard controls to create a new control that could be used in your programs. In Chapter 25, "Extending ActiveX Controls," you learned how to add properties, methods, and events to existing controls to give them greater functionality than they had before.
The two previous chapters focused on using existing pieces to create a new control. This chapter will demonstrate how to create a control totally from scratch by drawing the interface with graphics methods and by creating the properties, methods, and events of the control.
Creating a user-drawn control is the hardest method for creating your own ActiveX controls. However, it is also the most flexible because you are in control of everything. You can also do things with user-drawn controls that you cannot do with standard controls. For example, the control you create in this chapter is a command button that enables you to set the foreground and background colors of the button, something you simply cannot do with a regular command button. If you intend to create controls for use by other developers, here are a couple of general things to keep in mind:
Although a command button is a fairly simple example of creating a user-drawn control, it illustrates the main concepts for creating this type of control. The first major step you have to take is to determine the design of the control. To make sure your control works like a normal CommandButton control, you should examine a standard command button to note the behavior of the properties, methods, and events. For example, when you click a standard command button, the button's appearance changes so that it looks as if it has been pressed or pushed in. These lower-level procedures are the types of things you need to include in user-drawn controls.
The initial design of the button will be kept simple. This button control, named ColorBtn (short for "Color Button"), will have four key properties: BackColor, Caption, Font, and ForeColor. In addition, the button will respond to a minimal number of events: Click, GotFocus, LostFocus, MouseDown, and MouseUp.
As with all other custom controls you create, you need to start a new ActiveX control project. After creating the project, set the properties of the project and the User Control, as shown in Table 26.1.
Item | Setting |
Project Type | ActiveX Control |
Project Name | ColorButton |
Project Description | Color Enhanced Command Button |
User control Name property | ColorBtn |
User control Public property | True |
Since the user interface is drawn completely by you, you will create it in the code of the control. The code eeds to be placed in the control's Paint event, which is fired whenever the container (such as a form) that holds your control is redrawn. You can also force the Paint event by issuing the Refresh method. Keep in mind that your command button is really just a picture. You will be using graphics methods, such as the Line method, to control what the user sees. For example, when the user clicks your control, you will use lines to redraw the button so that it looks like it has been pressed. (For more information about graphics methods, refer to "Doing Graphics" on the CD-ROM.)
See "Using the Line and Shape Controls," found in "Doing Graphics" on this book's CD-ROM.
To draw a rectangular command button, you need only the Line and Print methods. In this case, the button will fill the entire space of the User Control area. Therefore, use the Height and Width of the control as parameters in the Line method. Drawing a colored button involves three steps:
The code for creating the body of the button is shown in Listing 26.1.
Dim inHeight As Integer Dim inWidth As Integer With UserControl `leave some room for the border inHeight = .Height - 10 inWidth = .Width - 10 `Set backcolor, draw a colored box .DrawWidth = 1 .FillColor = mBackColor .FillStyle = 0 UserControl.Line (0, 0)-(inWidth, inHeight), , B `Draw lower right lines .DrawWidth = 3 If bMouseDn = False Then .ForeColor = vbBlack Else .ForeColor = vbWhite UserControl.Line (0, inHeight)-(inWidth, inHeight) UserControl.Line (inWidth, 0)-(inWidth, inHeight) `Draw upper-left lines If bMouseDn = False Then .ForeColor = vbWhite Else .ForeColor = vbBlack UserControl.Line (0, 0)-(inWidth, 0) UserControl.Line (0, 0)-(0, inHeight) End With
This code should be fairly easy to follow. It simply draws a box and some lines to represent the command button. Note that the button's color is determined by a variable, mBackcolor, which will hold the contents of the BackColor property. This variable should be declared in the General Declarations section so that it can be set from another procedure. You also have to declare a Boolean variable, bMouseDn, to control whether the button is drawn "raised" or "pressed."
NOTE: Buttons like those in Office 97 and Internet Explorer are very similar to the button you are creating in this chapter. Although a free ActiveX control called the "Soft Button" exists on the Microsoft Web site (www.microsoft.com), it will not be very hard to create an Explorer-like button by using the techniques described here.
Figure 26.1 shows how this basic button would look on the form of a test project.
FIG. 26.1
The custom button is a working control with a unique appearance.
After you have drawn the body of the button, you need to draw the caption on the button. To draw the caption, you need to use the Print method. So that your button is similar to a standard command button, you need to add code to center the caption in the button. To do this, follow these steps:
The steps defined previously are illustrated in Listing 26.2.
With UserControl .ForeColor = mForeColor .CurrentX = (.Width - .TextWidth(m_Caption)) / 2 If .CurrentX < 5 Then .CurrentX = 5 .CurrentY = (.Height - .TextHeight(m_Caption)) / 2 If .CurrentY < 5 Then .CurrentY = 5 UserControl.Print m_Caption End With
This code, along with the previous listing, should be placed in the Paint event. Whenever you need to redraw the button in a different state, you can call the UserControl_Paint event procedure.
The final appearance of the ColorBtn control is shown in Figure 26.2.
FIG. 26.2
The caption is centered on the button and is printed in the requested foreground
color.
You should always remember to initialize the variables that are used in the control for this; you need to place the code in Listing 26.3 in the Initialize event of the user control.
Private Sub UserControl_Initialize() mBackColor = vbCyan mForeColor = vbBlue UserControl.BackColor = mBackColor UserControl.ForeColor = mForeColor End Sub
As stated previously, the design of the command button will be kept simple. The four key properties of the button are the BackColor, Caption, Font, and ForeColor properties. Three of these properties--BackColor, Font, and ForeColor--will be tied to the corresponding properties of the user control. In addition, the BackColor and ForeColor properties will be stored as variables for use in the code.
By using the ActiveX Control Interface Wizard, it is easy to create the properties that you need. Just be sure to map all the properties, except Caption, to those in the UserControl object. The wizard creates the Property Let and Property Get procedures for the four properties. Take, for example, the Property Get procedure for the control's BackColor property:
Public Property Get BackColor() As OLE_COLOR BackColor = UserControl.BackColor End Property
This procedure simply returns the background color of the user control and can be used as is. However, you will need to add an extra line to the Property Let procedure:
Public Property Let BackColor(ByVal New_BackColor As OLE_COLOR) UserControl.BackColor() = New_BackColor mBackColor = UserControl.BackColor PropertyChanged "BackColor" End Property
Notice that in this code, a line was added to store the color in the variable mBackColor. This variable, declared in the General Declarations section, is used by code in the Paint event. The other properties, shown in Listing 26.4, are coded in a similar fashion.
Public Property Get Font() As Font Set Font = UserControl.Font End Property Public Property Set Font(ByVal New_Font As Font) Set UserControl.Font = New_Font PropertyChanged "Font" End Property Public Property Get ForeColor() As OLE_COLOR ForeColor = UserControl.ForeColor End Property Public Property Let ForeColor(ByVal New_ForeColor As OLE_COLOR) UserControl.ForeColor() = New_ForeColor mForeColor = UserControl.ForeColor PropertyChanged "ForeColor" End Property Public Property Get Caption() As Variant Caption = m_Caption End Property Public Property Let Caption(ByVal New_Caption As Variant) m_Caption = New_Caption UserControl_Paint PropertyChanged "Caption" End Property
NOTE: Although you need to declare the variables mForeColor and mBackColor, the wizard declares m_Caption for you automatically. The reason for this difference is that the Caption property is not mapped to the UserControl object. You also might want to set the constant for the default caption name, m_def_Caption, to something other than 0. "ColorBtn" would be an appropriate choice.
The wizard also creates the code for the WriteProperties and ReadProperties events so that the property values can be saved in the PropertyBag object.
The wizard also will be used to create the events for the control. This can be done at the same time as when you create the properties, or you can simply run the wizard again. Remember that only the Click, GotFocus, LostFocus, MouseDown, and MouseUp events are needed for the control. As it turns out, the GotFocus and LostFocus events are included in the custom control automatically, so you only need to be concerned with the other three. After you select the needed events, you can map them to the corresponding events in the user control. The wizard then will create the basic code to define and raise the events.
After the wizard creates the skeleton code, make an addition to the code for the MouseDown and MouseUp events. Since you want your custom button to behave similarly to a standard command button, change the appearance of the button as it is pressed. You do this by drawing black lines along the top and left edges of the button when the MouseDown event is fired and by redrawing the white lines along those edges when the MouseUp event is fired. This will be coded by setting the Boolean variable bMouseDn and then running the code in the User Control's Paint event. After you have made the additions to these two events, the event code for the ColorBtn control will look like the code in Listing 26.5.
Private Sub UserControl_MouseDown(Button As Integer, _ Shift As Integer, X As Single, Y As Single) bMouseDn = True UserControl_Paint RaiseEvent MouseDown(Button, Shift, X, Y) End Sub Private Sub UserControl_MouseUp(Button As Integer, _ Shift As Integer, X As Single, Y As Single) bMouseDn = False UserControl_Paint RaiseEvent MouseUp(Button, Shift, X, Y) End Sub
NOTE: It is important that you do not confuse the events discussed here with the events of the ColorBtn control, as seen from the user's perspective. The previous code executes when the UserControl object receives mouse events. The last statement, RaiseEvent, fires the corresponding event in the ColorBtn control, executing any code the user may have placed there.
Figure 26.3 shows the pressed state of the ColorBtn control.
FIG. 26.3
Black lines give the indication of a pressed button.
The final thing you will do for the design of your ColorBtn control is to create the Property Pages so that the user can set the properties of the control easily. Use the Property Page Wizard to create the pages and follow these steps:
At this point, the design of the ColorBtn control is complete. You now are ready to test it in a program. You first need to add a Standard EXE project to the project group containing the ColorBtn. You then need to close the ColorBtn design window to make the control available to your project.
Once the button is available for use, you can draw the control on your form just like any other control. As you draw the button, you will see the typical rubber band box indicating the size of the control. When you release the mouse button, the control will be drawn using the default colors and caption. This is shown in Figure 26.4.
FIG. 26.4
A new instance of the ColorBtn control on a form.
After the control is drawn, you can move and resize it like you would any standard control. Try it and see how it works.
After the button is placed on the form, set the values of the properties. You can, of course, set the properties from the Properties window. One thing to notice is that if you placed a description in the Caption property when you defined it in the Wizard, this description shows up in the area below the properties list when the Caption property is selected. This description is another way to help your users work with your custom control.
Another way to set the properties of your control is to use the Property Pages you created. The dialog box, shown in Figure 26.5, enables you to set the Caption, BackColor, ForeColor, and Font properties of the control. The Paint event is fired whenever you close the Property Pages. At this time, the effects of the new properties are shown.
FIG. 26.5
Property Pages provide an organized way for users to set properties of a control.
Writing code for the events of the custom control is like writing any other event code. You can double-click the control to access the Code window and then begin writing code. Just to make sure that the Click event of the ColorBtn control works, place a message box in the event procedure that announces the button has been clicked. This code is shown in the following line:
MsgBox "You clicked the ColorBtn control."
You now can test your control by pressing F5 to run the test program. Try clicking the ColorBtn to make sure that the events work correctly. If things are not working right, use the normal debugging techniques to find the errors in the control. After you have finished testing and debugging the control, you are ready to compile your control and make it available for use in other projects.
See "Making Your Program Bug-Free," Chapter 8
After you have created a rectangular button, you may want to try your hand at creating other shapes. For example, you could draw a button that looks like a circle or ellipse. Or, you could draw a triangular button. In fact, you can use any shape that you can create with the graphics methods. The code in Listing 26.6 could be the basis for a circular button. Figure 26.6 shows you how this button would look on a form.
FIG. 26.6
You can draw other button shapes such as a circle.
Dim inHeight As Integer Dim inWidth As Integer Dim CircDim As Integer With UserControl inHeight = .Height - 10 inWidth = .Width - 10 If inHeight > inWidth Then CircDim = inWidth / 2 Else CircDim = inHeight / 2 End If .FillColor = mBackColor .FillStyle = 0 UserControl.Circle (CircDim, CircDim), CircDim `Print caption .ForeColor = mForeColor .CurrentX = CircDim - .TextWidth(m_Caption) / 2 If .CurrentX < 5 Then .CurrentX = 5 .CurrentY = CircDim - .TextHeight(m_Caption) / 2 If .CurrentY < 5 Then .CurrentY = 5 UserControl.Print m_Caption End With
This chapter has shown you the basics of creating a user-drawn control. While user-drawn controls involve a lot of work, they are very flexible because the programmer is in charge of everything. This chapter demonstrated how to use a programmer-defined Paint event to change the appearance of your control. You also learned that modifying the output from the ActiveX Control Interface Wizard is an easy way to produce the effects desired. To find out more about the other aspects of creating controls, see the following chapters:
© Copyright, Macmillan Computer Publishing. All rights reserved.