|
-
Sep 9th, 2004, 08:37 AM
#1
More articles to the new site
Since I'm too lazy to look for the old topic, I just post into a new one. So, here we have a guide to usercontrols for beginners.
---
Usercontrols
Sooner or later you find out VB's default controls aren't enough: you need more. You can take a look in the OCXs, but there is a major disadvantage in them: you have to include the file with your program setup. There is also a lot of different versions of the OCXs and it just might happen there are times when your application just doesn't start working and the user is confused and might even remove the program because it doesn't work.
A solution this is to create your own controls. Once you get used to the basics, it is relatively easy in most cases. And once you've created a user control, you can always use it in your other programs. At worst, user controls can be very complex on how they work, but most times controls are like small applications.
User controls have three main things you need to notice:
- you can declare events, and you must manually raise them too
- controls always have properties: Property Get, Let and Set
- property bags - these are used to store the control default settings set by the programmer who uses the control
And here the same told more practically.
If you want your control to have Private Sub ControlName_Click(), you must declare event Public Event Click() and then have RaiseEvent Click in your UserControl_Click()
If you want the control to have some customizable property, such as BackColor, you must have Property Get and Property Let, an inner variable m_BackColor holding the information (a good programming habit in the case) and also code for propertybags at UserControl_ReadProperties and UserControl_WriteProperties. Also, you need to initialize the properties. Sample code for this:
VB Code:
'just a reminder :)
Option Explicit
'for an almost complete list of these, please see Object Browser > SystemColorConstants
'there are a few more, the ones you see are supported by Windows 95 and NT4
Private Const m_def_BackColor As Long = vbButtonFace
Dim m_BackColor As Long
'we use OLE_COLOR so we don't see just a decimal value
'in the control property window when we are using the control
Public Property Get BackColor() As OLE_COLOR
BackColor = m_BackColor
End Property
'you can title NewColor as you want
Public Property Let BackColor(ByVal NewColor As OLE_COLOR)
m_BackColor = NewColor
UserControl.BackColor = NewColor
'in most cases you also need to redraw your control
'this happens simply by calling your redrawing sub
End Property
Private Sub UserControl_InitProperties()
'the first initialization, because ReadProperties doesn't get called in design time
'when you place the object on the form the first time
m_BackColor = m_def_BackColor
End Sub
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
'you could use something else than "BackColor", but I recommend to use the standard names
m_BackColor = PropBag.ReadProperty("BackColor", m_def_BackColor)
End Sub
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
'the "BackColor" must match with the code found at ReadProperties
PropBag.WriteProperty "BackColor", m_BackColor, m_def_BackColor
End Sub
Actually, with just the above, you can make up your first usercontrol! Try it out! Make a new fresh usercontrol, add the code, close the usercontrol and add it into the form. Then see what you can do with it.
To make a little more use with it, lets add four common events: Click, MouseDown, MouseMove and MouseUp
VB Code:
'in the user control declarations
Public Event Click()
Public Event MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Public Event MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Public Event MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
RaiseEvent MouseDown(Button, Shift, X, Y)
End Sub
Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
RaiseEvent MouseMove(Button, Shift, X, Y)
End Sub
Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
RaiseEvent MouseUp(Button, Shift, X, Y)
End Sub
After adding this code and testing it out, you should see these four events being available for use. Please note while making your own events that you must call RaiseEvent somewhere or the event will not ever occur. Also, if you don't declare the events (Public Event Click...), the events are not available at all and you also get an error when you are trying to call RaiseEvent.
Now, based on the property code above, add a new property: ForeColor. At simplest you can just double the code and then change all Back to Fore; and you're done. To make up some challenge, figure out something that show you visually the new ForeColor property is alive and working.
Once done, brace yourself: you have just learned the basics!
---
Too long article, have to split into two posts...
-
Sep 9th, 2004, 08:37 AM
#2
A more complete example: progress yourself
Now that we're done with the very first example, you probably want to go into something more advanced. There are many missing controls in VB, one of them being a progress bar: for that you'd need the Microsoft Windows Common Controls OCX. This is quite a price for getting a mere progress bar into your project. If you don't need ListView or TreeView, the OCX might feel like a big price. One other noticeable thing in the Windows' progress bar is that it is really slow in smooth mode. If you have a time critical code and want to see the progress smoothly, it just might prove to be expensive to use the OCX's progress bar on a lower end computer.
What properties does a progress bar need? After a while of thinking, if you don't cheat by reading all this here, you see we need atleast BackColor, ForeColor, Min, Max and Value. As for events, we need none for a simple progress bar.
Then the last question: how to make it in practise? For this I have a very simple suggestion: use a frame with BorderStyle set to none, sized the same size the usercontrol is and move it from outside the control to show progress. This is very fast and lightweight, and most imporant of all, easy to do.
At this point, I give you two paths to follow: either make it completely yourself, you learn a lot more that way, and use my code below for reference only for the very problematic parts where you can't figure something out after hours of thinking - or choose the easy path and copy the code. It is up to you what way you want to go.
The code below is flawless on what it does. I've taken care of every possible error/problem condition. For example, I allow Min to be bigger than Max. I've also done some optimization by using the internal helper variables: as these don't need to be counted every time RefreshProgress is called, but they're changed only when the values are changed, thus you can't just find nothing big to complain about on the speed side.
I decided to use Currency as the datatype for a reason: it can be bigger than Long and it can also take in up to four decimals. This maximizes the ease of use, because you can give about any values as the Min and Max and then just change the Value without any extra calculation: Common Controls progress bar is limited to Integer.
VB Code:
Option Explicit
'default property settings
Private Const m_def_BackColor As Long = vbHighlightText
Private Const m_def_ForeColor As Long = vbHighlight
Private Const m_def_Min As Currency = 0
Private Const m_def_Max As Currency = 10000
Private Const m_def_Value As Currency = 0
'property variables
Dim m_BackColor As Long
Dim m_ForeColor As Long
Dim m_Min As Currency
Dim m_Max As Currency
Dim m_Value As Currency
'helper variables
Dim i_Max As Currency
Dim i_Value As Currency
Public Property Get BackColor() As OLE_COLOR
BackColor = m_BackColor
End Property
Public Property Let BackColor(ByVal NewColor As OLE_COLOR)
m_BackColor = NewColor
Frame1.BackColor = NewColor
End Property
Public Property Get ForeColor() As OLE_COLOR
ForeColor = m_ForeColor
End Property
Public Property Let ForeColor(ByVal NewColor As OLE_COLOR)
m_ForeColor = NewColor
UserControl.BackColor = NewColor
End Property
Public Property Get Min() As Currency
Min = m_Min
End Property
Public Property Let Min(ByVal NewValue As Currency)
m_Min = NewValue
'Min can't be same as Max
If m_Min = m_Max Then m_Max = m_Min + 1
'make sure we have a valid value
If m_Min < m_Max Then
'Min is smaller than Max
If m_Value < m_Min Then m_Value = m_Min: i_Value = Abs(m_Value - m_Min)
Else
'Min is bigger than Max
If m_Value > m_Min Then m_Value = m_Min: i_Value = Abs(m_Value - m_Max)
End If
'internal helper variable for easing calculating the progress
'internal Min is always zero!
i_Max = Abs(m_Max - m_Min)
'make the changes visible
RefreshProgress
End Property
Public Property Get Max() As Currency
Max = m_Max
End Property
Public Property Let Max(ByVal NewValue As Currency)
m_Max = NewValue
'Max can't be same as Min
If m_Min = m_Max Then m_Min = m_Max - 1
'make sure we have a valid value
If m_Min < m_Max Then
'Max is bigger than Min
If m_Value > m_Max Then m_Value = m_Max: i_Value = Abs(m_Value - m_Min)
Else
'Max is smaller than Min
If m_Value < m_Max Then m_Value = m_Max: i_Value = Abs(m_Value - m_Max)
End If
'internal helper variable for easing calculating the progress
'internal Min is always zero!
i_Max = Abs(m_Max - m_Min)
'make the changes visible
RefreshProgress
End Property
Public Property Get Value() As Currency
Value = m_Value
End Property
Public Property Let Value(ByVal NewValue As Currency)
'error detection: check for a proper value (within current Min and Max)
If m_Min < m_Max Then
'min is smaller than max
Select Case NewValue
Case Is < m_Min
'we are getting a too small value
m_Value = m_Min
Case Is > m_Max
'we are getting a too big value
m_Value = m_Max
Case Else
'we are getting a proper value, update
m_Value = NewValue
End Select
'internal helper variable for easing calculating the progress
i_Value = Abs(m_Value - m_Min)
Else
'min is bigger than max
Select Case NewValue
Case Is > m_Min
'we are getting a too big value
m_Value = m_Min
Case Is < m_Max
'we are getting a too small value
m_Value = m_Max
Case Else
'we are getting a proper value, update
m_Value = NewValue
End Select
'internal helper variable for easing calculating the progress
i_Value = Abs(m_Value - m_Max)
End If
'make the changes visible
RefreshProgress
End Property
Private Sub RefreshProgress()
'thanks to the internal helper variables, counting the position is a piece of a cake
Frame1.Move UserControl.ScaleWidth / i_Max * i_Value, 0, UserControl.ScaleWidth, UserControl.ScaleHeight
End Sub
Private Sub UserControl_InitProperties()
m_BackColor = m_def_BackColor
m_ForeColor = m_def_ForeColor
m_Min = m_def_Min
m_Max = m_def_Max
m_Value = m_def_Value
End Sub
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
m_BackColor = PropBag.ReadProperty("BackColor", m_def_BackColor)
m_ForeColor = PropBag.ReadProperty("ForeColor", m_def_ForeColor)
m_Min = PropBag.ReadProperty("Min", m_def_Min)
m_Max = PropBag.ReadProperty("Max", m_def_Max)
m_Value = PropBag.ReadProperty("Value", m_def_Value)
'after getting all the settings, initialize stuff and make them visible
Frame1.BackColor = m_BackColor
UserControl.BackColor = m_ForeColor
'initialize helper variables
i_Max = Abs(i_Max - i_Min)
If m_Min < m_Max Then
'min is smaller than max
i_Value = Abs(m_Value - m_Min)
Else
'max is smaller than min
i_Value = Abs(m_Value - m_Max)
End If
'make the changes visible the first time
RefreshProgress
End Sub
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
PropBag.WriteProperty "BackColor", m_BackColor, m_def_BackColor
PropBag.WriteProperty "ForeColor", m_ForeColor, m_def_ForeColor
PropBag.WriteProperty "Min", m_Min, m_def_Min
PropBag.WriteProperty "Max", m_Max, m_def_Max
PropBag.WriteProperty "Value", m_Value, m_def_Value
End Sub
Well, that's the course for now. I hope this answers to most of your questions regarding usercontrols. There are still some stuff to find out, but this should guide you well to the beginning 
---
I didn't even realize it was that long!
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|