Platinum Edition Using Visual Basic 5

Previous chapterNext chapterContents


- 26 -
Creating a User-Drawn Control

You will see what the advantages are of drawing your own controls from scratch.
You will learn how to create the user interface, as well as events that respond to user actions.
You will see how to change the appearance of your control based on user events.

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:

Building the User-Drawn Command Button

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.

Starting the Project

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.

Table 26.1 Properties of the Project and Control

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

Creating the User Interface

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:

1. Draw a filled rectangular box the full size of the control, using the selected background color.

2. Draw a white line along the top and left edges of the control, and draw a black line along the bottom and right edges of the control. These lines give the button the standard "raised" appearance. (When the button is "pressed," you'll reverse the appearance by swapping the white and black lines.)

3. By using the Print method, draw a caption on the button.

The code for creating the body of the button is shown in Listing 26.1.

Listing 26.1 COLORBTN.CTL--Using the Line Method to Draw the Body of the Button

    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:

1. Use the TextHeight and TextWidth methods of the user control to determine the size of the caption.

2. Use the size of the caption and the size of the control to determine the coordinates for starting the printing.

3. Set the print color by setting the ForeColor property of the user control.

4. Use the Print method to display the caption.

The steps defined previously are illustrated in Listing 26.2.

Listing 26.2 COLORBTN.CTL--Using the Print Method to Write the Caption on the Button

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.

Listing 26.3 COLORBTN.CTL--Initializing the Variables of Your Control

Private Sub UserControl_Initialize()
   mBackColor = vbCyan
   mForeColor = vbBlue
   UserControl.BackColor = mBackColor
   UserControl.ForeColor = mForeColor
End Sub

Creating the Properties of the Button

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.

Listing 26.4 COLORBTN.CTL--Most of the Property Procedures Were Created by the Wizard

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.

Setting Up the Button's Events

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.

Listing 26.5 COLORBTN.CTL--Event Code Defined by the Wizard and Enhanced by You

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.

Creating Property Pages for the 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:

1. Add a General page to the pages.

2. Place the Caption property on the General page.

3. Verify that the BackColor and ForeColor properties are on the StandardColor page.

4. Verify that the Font property is on the StandardFont page.

Using the Button in a Program

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.

Drawing the Button

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.

Setting the Button's Properties

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

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."

Testing the Button

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

Trying Other Button Styles

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.

Listing 26.6 CIRCBTN.CTL--Other Button Shapes Can Be Achieved with the Appropriate Code

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

From Here...

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:


Previous chapterNext chapterContents


Macmillan Computer Publishing USA

© Copyright, Macmillan Computer Publishing. All rights reserved.