Results 1 to 2 of 2

Thread: More articles to the new site

  1. #1

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    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:
    1. 'just a reminder :)
    2. Option Explicit
    3.  
    4. 'for an almost complete list of these, please see Object Browser > SystemColorConstants
    5. 'there are a few more, the ones you see are supported by Windows 95 and NT4
    6. Private Const m_def_BackColor As Long = vbButtonFace
    7.  
    8. Dim m_BackColor As Long
    9.  
    10. 'we use OLE_COLOR so we don't see just a decimal value
    11. 'in the control property window when we are using the control
    12. Public Property Get BackColor() As OLE_COLOR
    13.     BackColor = m_BackColor
    14. End Property
    15.  
    16. 'you can title NewColor as you want
    17. Public Property Let BackColor(ByVal NewColor As OLE_COLOR)
    18.     m_BackColor = NewColor
    19.     UserControl.BackColor = NewColor
    20.     'in most cases you also need to redraw your control
    21.     'this happens simply by calling your redrawing sub
    22. End Property
    23.  
    24. Private Sub UserControl_InitProperties()
    25.     'the first initialization, because ReadProperties doesn't get called in design time
    26.     'when you place the object on the form the first time
    27.     m_BackColor = m_def_BackColor
    28. End Sub
    29.  
    30. Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
    31.     'you could use something else than "BackColor", but I recommend to use the standard names
    32.     m_BackColor = PropBag.ReadProperty("BackColor", m_def_BackColor)
    33. End Sub
    34.  
    35. Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
    36.     'the "BackColor" must match with the code found at ReadProperties
    37.     PropBag.WriteProperty "BackColor", m_BackColor, m_def_BackColor
    38. 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:
    1. 'in the user control declarations
    2. Public Event Click()
    3. Public Event MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    4. Public Event MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    5. Public Event MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    6.  
    7. Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    8.     RaiseEvent MouseDown(Button, Shift, X, Y)
    9. End Sub
    10.  
    11. Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    12.     RaiseEvent MouseMove(Button, Shift, X, Y)
    13. End Sub
    14.  
    15. Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    16.     RaiseEvent MouseUp(Button, Shift, X, Y)
    17. 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...

  2. #2

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654
    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:
    1. Option Explicit
    2.  
    3. 'default property settings
    4. Private Const m_def_BackColor As Long = vbHighlightText
    5. Private Const m_def_ForeColor As Long = vbHighlight
    6. Private Const m_def_Min As Currency = 0
    7. Private Const m_def_Max As Currency = 10000
    8. Private Const m_def_Value As Currency = 0
    9.  
    10. 'property variables
    11. Dim m_BackColor As Long
    12. Dim m_ForeColor As Long
    13. Dim m_Min As Currency
    14. Dim m_Max As Currency
    15. Dim m_Value As Currency
    16.  
    17. 'helper variables
    18. Dim i_Max As Currency
    19. Dim i_Value As Currency
    20.  
    21. Public Property Get BackColor() As OLE_COLOR
    22.     BackColor = m_BackColor
    23. End Property
    24.  
    25. Public Property Let BackColor(ByVal NewColor As OLE_COLOR)
    26.     m_BackColor = NewColor
    27.     Frame1.BackColor = NewColor
    28. End Property
    29.  
    30. Public Property Get ForeColor() As OLE_COLOR
    31.     ForeColor = m_ForeColor
    32. End Property
    33.  
    34. Public Property Let ForeColor(ByVal NewColor As OLE_COLOR)
    35.     m_ForeColor = NewColor
    36.     UserControl.BackColor = NewColor
    37. End Property
    38.  
    39. Public Property Get Min() As Currency
    40.     Min = m_Min
    41. End Property
    42.  
    43. Public Property Let Min(ByVal NewValue As Currency)
    44.     m_Min = NewValue
    45.     'Min can't be same as Max
    46.     If m_Min = m_Max Then m_Max = m_Min + 1
    47.     'make sure we have a valid value
    48.     If m_Min < m_Max Then
    49.         'Min is smaller than Max
    50.         If m_Value < m_Min Then m_Value = m_Min: i_Value = Abs(m_Value - m_Min)
    51.     Else
    52.         'Min is bigger than Max
    53.         If m_Value > m_Min Then m_Value = m_Min: i_Value = Abs(m_Value - m_Max)
    54.     End If
    55.     'internal helper variable for easing calculating the progress
    56.     'internal Min is always zero!
    57.     i_Max = Abs(m_Max - m_Min)
    58.     'make the changes visible
    59.     RefreshProgress
    60. End Property
    61.  
    62. Public Property Get Max() As Currency
    63.     Max = m_Max
    64. End Property
    65.  
    66. Public Property Let Max(ByVal NewValue As Currency)
    67.     m_Max = NewValue
    68.     'Max can't be same as Min
    69.     If m_Min = m_Max Then m_Min = m_Max - 1
    70.     'make sure we have a valid value
    71.     If m_Min < m_Max Then
    72.         'Max is bigger than Min
    73.         If m_Value > m_Max Then m_Value = m_Max: i_Value = Abs(m_Value - m_Min)
    74.     Else
    75.         'Max is smaller than Min
    76.         If m_Value < m_Max Then m_Value = m_Max: i_Value = Abs(m_Value - m_Max)
    77.     End If
    78.     'internal helper variable for easing calculating the progress
    79.     'internal Min is always zero!
    80.     i_Max = Abs(m_Max - m_Min)
    81.     'make the changes visible
    82.     RefreshProgress
    83. End Property
    84.  
    85. Public Property Get Value() As Currency
    86.     Value = m_Value
    87. End Property
    88.  
    89. Public Property Let Value(ByVal NewValue As Currency)
    90.     'error detection: check for a proper value (within current Min and Max)
    91.     If m_Min < m_Max Then
    92.         'min is smaller than max
    93.         Select Case NewValue
    94.             Case Is < m_Min
    95.                 'we are getting a too small value
    96.                 m_Value = m_Min
    97.             Case Is > m_Max
    98.                 'we are getting a too big value
    99.                 m_Value = m_Max
    100.             Case Else
    101.                 'we are getting a proper value, update
    102.                 m_Value = NewValue
    103.         End Select
    104.         'internal helper variable for easing calculating the progress
    105.         i_Value = Abs(m_Value - m_Min)
    106.     Else
    107.         'min is bigger than max
    108.         Select Case NewValue
    109.             Case Is > m_Min
    110.                 'we are getting a too big value
    111.                 m_Value = m_Min
    112.             Case Is < m_Max
    113.                 'we are getting a too small value
    114.                 m_Value = m_Max
    115.             Case Else
    116.                 'we are getting a proper value, update
    117.                 m_Value = NewValue
    118.         End Select
    119.         'internal helper variable for easing calculating the progress
    120.         i_Value = Abs(m_Value - m_Max)
    121.     End If
    122.     'make the changes visible
    123.     RefreshProgress
    124. End Property
    125.  
    126. Private Sub RefreshProgress()
    127.     'thanks to the internal helper variables, counting the position is a piece of a cake
    128.     Frame1.Move UserControl.ScaleWidth / i_Max * i_Value, 0, UserControl.ScaleWidth, UserControl.ScaleHeight
    129. End Sub
    130.  
    131. Private Sub UserControl_InitProperties()
    132.     m_BackColor = m_def_BackColor
    133.     m_ForeColor = m_def_ForeColor
    134.     m_Min = m_def_Min
    135.     m_Max = m_def_Max
    136.     m_Value = m_def_Value
    137. End Sub
    138.  
    139. Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
    140.     m_BackColor = PropBag.ReadProperty("BackColor", m_def_BackColor)
    141.     m_ForeColor = PropBag.ReadProperty("ForeColor", m_def_ForeColor)
    142.     m_Min = PropBag.ReadProperty("Min", m_def_Min)
    143.     m_Max = PropBag.ReadProperty("Max", m_def_Max)
    144.     m_Value = PropBag.ReadProperty("Value", m_def_Value)
    145.     'after getting all the settings, initialize stuff and make them visible
    146.     Frame1.BackColor = m_BackColor
    147.     UserControl.BackColor = m_ForeColor
    148.     'initialize helper variables
    149.     i_Max = Abs(i_Max - i_Min)
    150.     If m_Min < m_Max Then
    151.         'min is smaller than max
    152.         i_Value = Abs(m_Value - m_Min)
    153.     Else
    154.         'max is smaller than min
    155.         i_Value = Abs(m_Value - m_Max)
    156.     End If
    157.     'make the changes visible the first time
    158.     RefreshProgress
    159. End Sub
    160.  
    161. Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
    162.     PropBag.WriteProperty "BackColor", m_BackColor, m_def_BackColor
    163.     PropBag.WriteProperty "ForeColor", m_ForeColor, m_def_ForeColor
    164.     PropBag.WriteProperty "Min", m_Min, m_def_Min
    165.     PropBag.WriteProperty "Max", m_Max, m_def_Max
    166.     PropBag.WriteProperty "Value", m_Value, m_def_Value
    167. 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
  •  



Click Here to Expand Forum to Full Width