Creating a Color Control |
In this article, you will learn how to initialize and terminate controls and how to use unique properties, methods, and events. To simplify the discussion. We will not use the Wizard but will implement all the properties and methods manually so that you'll get some experience in editing controls.
Let's start by creating a color control. Follow these steps:
| DragIcon | DragMode |
| Height | HelpContextID |
| Index | Left |
| TabIndex | TabStop |
| Tag | ToolTipText |
| Top, Left | Visible |
| WhaIsThisHelp ID | Width |
These properties are actually provided by the container. The left property is determined by the container and has meaning only in the context of a container. Likewise, the TabIndex and TabStop properties aren't managed by the control itself, because the control doesn't know what other controls exist on the Form. Only the Form does, and therefore the Form must maintain these properties for its controls.
Test a few of these properties. Assign the value "My Color Control" to the ToolTipText property. Run the application, and then rest the pointer for a second over the control. The string you entered is displayed in a ToolTip box. In a similar manner, you can test the Tag property by assigning a string to it, or you can test the Index property by creating multiple instances of the same control on the Form with the same name and a different Index value. There's not a single line of code you should add to the control to implement these properties.
Let's add a property to our Color control. We'll call it Title, and we'll store its value internally to the m_Title private property. Select UserControl1 in the Project window, and in the Code window, insert the following declaration:
Private m_Title As String
and then the procedures:
Public Property Get Title() As String
Title = m_Title
End Property
Public Property Let Title(ByVal vNewTitle As String)
m_Title = vNewTitle
End Property
Close the UserControl design window and the Code window, switch to the test Form, select
the new control, and look up its new property in the Properties window. The mere presence
of the Let and Get procedures is all that Visual Basic needs to add a property to the
control. Enter a new value in the Title property's box (For example: Control Color. As
expected, the title won't appear on the control.
We must also write a few lines of code to display the Title. Switch back to the UserControl window, double-click it to open the Code window, and in the paint event, enter the following:
Private Sub UserControl_Paint()
UserControl.CurrentX = 0
UserControl.CurrentY = 0
UserControl.Print m_Title
End Sub
| Tip | The first two statements aren't really needed to display something at the control's upper left corner. but you must set them accordingly if you want to display something else where on the control. |
Switch back to the test Form. If you have any other custom control on the Form, delete them.
Add an instance of the custom control (it will automatically be named UserControl1 unless you have changed the name of the UserControl object), and then assign a value to the Title property. Set the title to My Color Control, for instance. The title won't appear the moment you enter it because the paint event isn't triggered when a property changes values. You must resize the control to force paint event and display the title. If you don't like the font, change the UserControl's font property (our control doesn't have a Font property yet).
Every time a new property is set, the Property let procedure is invoked. You must, therefore, call the Paint method from within the Property Let procedure so that the title is displayed as soon as it's entered. Switch back to the UserControl, add the following line to the Property Let Title procedure:
userControl_Paint
Now assign a value to the Title property and watch the string appear on the control.
Now, press F5 to run the application. The title won't appear on the control. It was there at design time, but it disappeared at runtime. You probably want to stop the application and look up the value of the Title property to make sure it still contains its value. But you're in for a surprise. The Title property's value is a blank string like before. It wasn't your fault, so don't repeat the process. Any properties set at design time lose their value at runtime. It's a strange behavior, but this how controls work.
Your experience with Visual Basic tells you that any properties set at design time keep their values at runtime. To make this happen you must first save the property values to Property Bag. What's not so easy to guess is when an action must take place.
When you place an instance of a control on the Form, the following events take place:
Initialize initializes the design-time instance of the control.
initProperties assigns initial values to the properties.
When you switch from design time to runtime, the following events take place:
WriteProperties saves the properties listed in the Properties window.
Terminate terminates the design-time instance of the control.
Initialize initializes a new, runtime instance of the control.
ReadProperties reads the saved properties.
When you switch from runtime to design time, the following events take place:
Initialize initializes the design-time instance of the control.
ReadProperties Reads the values from the Properties window and assigns them to the corresponding properties.
| Tip | When you switch from runtime to design-time mode, no WriteProperties event takes place. As expected, Visual Basic doesn't save properties that changed at runtime and resets the ActiveX control to the properties set in the Properties window at design time. |
To maintain the values of the properties when the control switches from design to runtime, you must add a few lines of code in the ReadProperties and WriteProperties events. We have looked at how property values are written to and read from the Property Bag object, so here's the code for the Title property:
Private Sub UserControl_ReadProperties(PropBag
As PropertyBag)
Title = PropBag.ReadProperty("Title",
"Control Title")
End Sub
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
PropBag.WriteProperty "Title",
m_Title, "Control Title"
End Sub
You can use two events to maintain the control - Initialize and initProperties. The ActiveX User Interface Wizard does it so well for us. The initialize event can be used to enter initialization code that doesn't involve properties. If you try to set a property value or do something on the control, you'll get the following error message:
Object Required
The UserControl object is being initialized. It doesn't exist yet. That's why UserControl.Print "Control" works when executed form within other events, but not from within the Initialize event.
So, what can you do from within this event? Not match. You can assign initial values o the private variables of the control, but you can't access the control's properties, not event the Ambient object.
The event of interest is the initProperties event, which takes place after the control is created. This behavior may strike you as strange: The initialize event takes place every time you switch between design and runtime mode, but the initProperties event doesn't follow.
In the InitProperties event, you can insert initialization code that controls the appearance of a "newborn" control. For instance, you can determine what happens if the user places the control on a Form by double-click on its icon instead of actually drawing the control on the Form. Visual Basic places an instance of the control on the Form, and it will have a certain size (which is the same for all controls). If your control contains a long default title, a shape, or any element you want to be entirely visible, you can adjust the initial size of the control with a couple of statements such as the following:
UserControl.Width = 2400
UserControl.Height = 1200
When your control is placed on a Form with a double-click of its icon, its initial size is 2400 by 1200 twips.
The Extender and Ambient objects are also available from within the InitProperties control, because the control has been sited. You can display a title on the control in the same font as the container's font, as follows:
Set Font = Ambient.Font
UserControl.PropertyChanged "VBGreatone"
These two lines display the string "VBGratone" in the control's upper left corner, in the font of the container. In addition, your contro's font will also be initially set to the Form's font.
As you have learned, the UserControl object is basically a Form on which you can place other controls, draw shapes, display text, and detect events, It even has properties such as AutoRedraw and ScaleMode, which make it suitable for drawing at runtime. But it's not called Form; it's call UserControl. In addition, it has a few properties that are unique ActiveX controls, and we are going to look at them in this section.
CanGetFocus Set this property to True if the control can receive the focus, either with the mouse or with the Tab key. A user control can get the focus if the UserControl object gets the focus or if one of its constituent controls can get the focus. If the control can get the Focas, the EnterFocus and ExitFocus events are triggered every time the focus is moved in or out of the control.
ControlContainer If this property is set to True, the user control can become a container for other controls. Normally, the controls placed on a container are grouped with the container, and they all move together. When you reposition the container control on the Form, all the controls contained in it are moved along.
By default, a user control is not a container. In other words, it is possible to draw a Command Button that lies half on the user control and half outside. To change this behavior, set the ControlContainer property to True.
Alignable If the Alignable property is set to True, the user control has an Align property at design time. The Align property determines whether and how the control is aligned on the Form.
InvisibleAtRuntime some controls, the Timer being the most typical example, are invisible at runtime. If your user control does not have a user interface and need not appear on the Form, set its InvisibleAtRuntime property to True.
ToolboxBitmap use this property to display a bmp file in the toolbox in place of the ActiveX Control generic icon. The ToolboxBitmap property's value is a BMP file's path name, but the bitmap is stored in the control and distributed with it.
AccessKeys You use this property to specify which keys will act as how keys for this control. If you want the user to move the focus instantly to your control by pressing a hot-key combination (Alt+key), assign the key value to the Accesskeys property.
Add and place the following controls on the UserControl form like Pic 1:
Pic 1:

Set The follow properties:
Paste the following code in to the usercontrol's code:
'Default Property Values:
Const m_def_RedComponent = 128
Const m_def_GreenComponent = 128
Const m_def_BlueComponent = 128
Const m_def_SelectedColor = &HFFFF00
'Property Variables:
Dim m_RedComponent As Byte
Dim m_GreenComponent As Byte
Dim m_BlueComponent As Byte
Dim m_SelectedColor As OLE_COLOR
' Events
Event RedChanged()
Event GreenChanged()
Event BlueChanged()
Private Sub Component_Change(Index As Integer)
UpdateColors Index
UpdateValues
End Sub
Private Sub Component_Scroll(Index As Integer)
UpdateColors Index
UpdateValues
End Sub
Public Property Get BackColor() As OLE_COLOR
BackColor = UserControl.BackColor
End Property
Public Property Let BackColor(ByVal New_BackColor As OLE_COLOR)
UserControl.BackColor() = New_BackColor
PropertyChanged "BackColor"
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
PropertyChanged "ForeColor"
End Property
Public Property Get Enabled() As Boolean
Enabled = UserControl.Enabled
End Property
Public Property Let Enabled(ByVal New_Enabled As Boolean)
UserControl.Enabled() = New_Enabled
PropertyChanged "Enabled"
End Property
Public Property Get BackStyle() As Integer
BackStyle = UserControl.BackStyle
End Property
Public Property Let BackStyle(ByVal New_BackStyle As Integer)
UserControl.BackStyle() = New_BackStyle
PropertyChanged "BackStyle"
End Property
Public Property Get BorderStyle() As Integer
BorderStyle = UserControl.BorderStyle
End Property
Public Property Let BorderStyle(ByVal New_BorderStyle As Integer)
UserControl.BorderStyle() = New_BorderStyle
PropertyChanged "BorderStyle"
End Property
Public Sub Refresh()
UserControl.Refresh
End Sub
Public Property Get SelectedColor() As OLE_COLOR
SelectedColor = m_SelectedColor
End Property
Public Property Let SelectedColor(ByVal New_SelectedColor As OLE_COLOR)
m_SelectedColor = New_SelectedColor
Picture1.BackColor = m_SelectedColor
m_RedComponent = SelectedColor And &HFF
m_GreenComponent = (SelectedColor / 256) And &HFF
m_BlueComponent = (SelectedColor / (256 ^ 2)) And &HFF
UpdateScrollbars
PropertyChanged "RedComponent"
PropertyChanged "GreenComponent"
PropertyChanged "BlueComponent"
PropertyChanged "SelectedColor"
End Property
'Initialize Properties for User Control
Private Sub UserControl_InitProperties()
m_SelectedColor = m_def_SelectedColor
m_RedComponent = m_def_RedComponent
m_GreenComponent = m_def_GreenComponent
m_BlueComponent = m_def_BlueComponent
End Sub
'Load property values from storage
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
UserControl.BackColor = PropBag.ReadProperty("BackColor",
&H8000000F)
UserControl.ForeColor = PropBag.ReadProperty("ForeColor",
&H80000012)
UserControl.Enabled = PropBag.ReadProperty("Enabled", True)
UserControl.BackStyle = PropBag.ReadProperty("BackStyle", 1)
UserControl.BorderStyle = PropBag.ReadProperty("BorderStyle",
0)
m_SelectedColor = PropBag.ReadProperty("SelectedColor",
m_def_SelectedColor)
m_RedComponent = PropBag.ReadProperty("RedComponent",
m_def_RedComponent)
m_GreenComponent = PropBag.ReadProperty("GreenComponent",
m_def_GreenComponent)
m_BlueComponent = PropBag.ReadProperty("BlueComponent",
m_def_BlueComponent)
UpdateScrollbars
End Sub
Private Sub UserControl_Resize()
UserControl.Width = Component(0).Left + Component(0).Width + 2 *
Picture1.Left
UserControl.Height = Picture1.Width + 3 * Picture1.Top
End Sub
'Write property values to storage
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
Call PropBag.WriteProperty("BackColor",
UserControl.BackColor, &H8000000F)
Call PropBag.WriteProperty("ForeColor",
UserControl.ForeColor, &H80000012)
Call PropBag.WriteProperty("Enabled", UserControl.Enabled,
True)
Call PropBag.WriteProperty("BackStyle",
UserControl.BackStyle, 1)
Call PropBag.WriteProperty("BorderStyle",
UserControl.BorderStyle, 0)
Call PropBag.WriteProperty("SelectedColor", m_SelectedColor,
m_def_SelectedColor)
Call PropBag.WriteProperty("RedComponent", m_RedComponent,
m_def_RedComponent)
Call PropBag.WriteProperty("GreenComponent",
m_GreenComponent, m_def_GreenComponent)
Call PropBag.WriteProperty("BlueComponent", m_BlueComponent,
m_def_BlueComponent)
End Sub
Public Property Get RedComponent() As Byte
RedComponent = m_RedComponent
End Property
Public Property Let RedComponent(ByVal New_RedComponent As Byte)
m_RedComponent = New_RedComponent
UpdateScrollbars
PropertyChanged "RedComponent"
End Property
Public Property Get GreenComponent() As Byte
GreenComponent = m_GreenComponent
End Property
Public Property Let GreenComponent(ByVal New_GreenComponent As Byte)
m_GreenComponent = New_GreenComponent
UpdateScrollbars
PropertyChanged "GreenComponent"
End Property
Public Property Get BlueComponent() As Byte
BlueComponent = m_BlueComponent
End Property
Public Property Let BlueComponent(ByVal New_BlueComponent As Byte)
m_BlueComponent = New_BlueComponent
UpdateScrollbars
PropertyChanged "BlueComponent"
End Property
Private Sub UpdateColors(Index As Integer)
Select Case Index
Case 0: m_RedComponent
= Component(0).Value
PropertyChanged "RedComponent"
RaiseEvent RedChanged
Case 1:
m_GreenComponent = Component(1).Value
PropertyChanged "GreenComponent"
RaiseEvent GreenChanged
Case 2: m_BlueComponent
= Component(2).Value
PropertyChanged "BlueComponent"
RaiseEvent BlueChanged
End Select
Picture1.BackColor = RGB(Component(0).Value, Component(1).Value,
Component(2).Value)
Picture1.Refresh
m_SelectedColor = m_RedComponent + CLng(m_GreenComponent) * 256 +
CLng(m_BlueComponent) * 256 ^ 2
End Sub
Private Sub UpdateScrollbars()
Component(0).Value = m_RedComponent
Component(1).Value = m_GreenComponent
Component(2).Value = m_BlueComponent
Label4.Caption = m_RedComponent
Label5.Caption = m_GreenComponent
Label6.Caption = m_BlueComponent
End Sub
Private Sub UpdateValues()
Label4.Caption = m_RedComponent
Label5.Caption = m_GreenComponent
Label6.Caption = m_BlueComponent
End Sub
©1999-2000 VBGreatone. All rights reserved.