Visual Basic Banner Exchange

May 1998

Return to Article Index

Objects in Visual Basic 
By Guillermo Som 

(Translated by Joe LeVasseur  [Any mistakes, etc are probably by translator].)


Despite the fact that it has been more than two and a half years since the release of Visual Basic 4.0, there is an element that hasn't been sufficiently implemented, perhaps from lack of understanding. I'm referring to class modules- the VB gateway to the world of object oriented programming.

Don't get me wrong, I'm not saying that these "new" modules aren't used, I'm saying that perhaps they're  not as well understood as they should be. Luckily version five of Visual Basic improved classes in general, placing object oriented programming within our reach. Well, almost object oriented, I must say- I don't need a bunch purist zealots to fill my mailbox up with speeches about true object oriented programming languages.

Perhaps some of my readers will say "I've been using Visual Basic classes for ages", and that is fine, although some of us "abuse" classes- sometimes for snobbish reasons: since they're the latest and greatest we must use them ... I've seen more than one application that uses classes (objects) for situations that didn't really require them. I've also seen code that the use of an object could have saved a lot of headaches. The truth is that I didn't have to look very far for examples of both situations- I found them in my own code.

I believe that the most prevalent reason that classes are not used more extensively in Visual Basic projects is that they are not fully understood, it's not understood when to use them or when their use could be of benefit to our projects. This is quite strange, because the moment that we create a new project, we are working, directly or indirectly, consciously or unconsciously, with objects: assigning values to their properties and using their exposed methods. Knowing that, we should change our focus when starting a new project and plan it like a puzzle, with each piece being an object. The more independent each piece of the puzzle is, the better.

Let's look at a practical use of an object, (In the form of a class module) which can solve some problems we didn't even plan on. The following code snippet will allow us to show in the text portion of a combobox, while we're writing, the item in the listbox that most closely corresponds to what we're typing. At first, I implemented the procedure as public methods of a standard .BAS module.

Here's the code:

' Code in a standard BAS module
Option Explicit

Dim ComboBackspace As Boolean

Public Sub SomeCombo_KeyDown(KeyCode As Integer)
    If KeyCode = vbKeyDelete Then
        ComboBackspace = True
    Else
        ComboBackspace = False
    End If
End Sub

Public Sub SomeCombo_KeyPress(KeyAscii As Integer)
    'If BackSpace pressed, ignore that key
    If KeyAscii = vbKeyBack Then
        ComboBackspace = True
    Else
        ComboBackspace = False
    End If
End Sub

Public Sub SomeCombo_Change(ByVal sText As String, TheCombo As ComboBox)
    Dim i As Integer, L As Integer

    If Not ComboBackspace Then
        L = Len(sText)
        With TheCombo
            For i = 0 To .ListCount - 1
                If StrComp(sText, Left$(.List(i), L), 1) = 0 Then
                    .ListIndex = i
                    .Text = .List(.ListIndex)
                    .SelStart = L
                    .SelLength = Len(.Text) - .SelStart
                    Exit For
                End If
            Next
        End With
    End If
End Sub

To implement, simply do this:

Option Explicit

'Code for the ComboBox
Private Sub Combo1_Change()
    Static BeenHere As Boolean
    On Local Error Resume Next
    If Not BeenHere Then
        BeenHere = True
        SomeCombo_Change Combo1.Text, Combo1
        BeenHere = False
    End If
    Err = 0
End Sub

Private Sub Combo1_KeyDown(KeyCode As Integer, Shift As Integer)
    SomeCombo_KeyDown KeyCode
End Sub

Private Sub Combo1_KeyPress(KeyAscii As Integer)
    SomeCombo_KeyPress KeyAscii
End Sub

If you have more than one ComboBox control, use the routine the same way, simply changing the name of the control you're referring to. There's no problem with this method ... except it would be better if we could call the routine for all of them at the same time. Anyway, using a class which would take charge of each combo would free us from a lot of conflicts, for the simple reason that each of these objects created for each ComboBox would independently manage it's own variables. which is what we call "encapsulation". Well, on to the code:

'Code from the class
Option Explicit

Dim theCombo As ComboBox

Dim ComboErase As Boolean

Public Property Set Combo(ByVal NewCombo As ComboBox)
    Set theCombo = NewCombo
End Property

Public Sub KeyDown(KeyCode As Integer)
    If KeyCode = vbKeyDelete Then
        ComboErase = True
    Else
        ComboErase = False
    End If
End Sub

Public Sub KeyPress(KeyAscii As Integer)
    'If Backspace, ignore
    If KeyAscii = vbKeyBack Then
        ComboErase = True
    Else
        ComboErase = False
    End If
End Sub

Public Sub Change(ByVal sText As String)
    Dim i As Integer, L As Integer

    If Not ComboErase Then
        L = Len(sText)
        With theCombo
            For i = 0 To .ListCount - 1
                If StrComp(sText, Left$(.List(i), L), 1) = 0 Then
                    .ListIndex = i
                    .Text = .List(.ListIndex)
                    .SelStart = L
                    .SelLength = Len(.Text) - .SelStart
                    Exit For
                End If
            Next
        End With
    End If
End Sub
 
 

To use it, we create a reference to this type of object. Here's the implementation code.

'Code for the form
Option Explicit

Dim cCombo1 As cSearchCbo

Private Sub Form_Load()
    Set cCombo1 = New cSearchCbo
    Set cCombo1.Combo = Combo1
End Sub

Private Sub Combo1_Change()
    Static BeenHere As Boolean
    If Not BeenHere Then
        BeenHere = True
        cCombo1.Change Combo1.Text
        BeenHere = False
    End If
End Sub

Private Sub Combo1_KeyDown(KeyCode As Integer, Shift As Integer)
    cCombo1.KeyDown KeyCode
End Sub

Private Sub Combo1_KeyPress(KeyAscii As Integer)
    cCombo1.KeyPress KeyAscii
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Set cCombo1 = Nothing
End Sub

Using the class this way, each object takes care of it's own combo and if we want to expand it's functionality, we would feel secure that any variable values we want to protect. (For example: for example a copy of the items in the list.), will remain "inside" the object. But using the class this way, basically we are using the code as we did with the .BAS module, except each ComboBox will be assigned in a new instance of the class, maintaining its own copy of variables. Although it's not a good way to do it, it would provide us with "privacy" for our variables to if we created a new instance of the class with a different name for each ComboBox. For example:

    Dim cCombo2 As cSearchCbo
    Set cCombo2 = New cSearchCbo
    Set cCombo2.Combo = Combo2

Private Sub Combo2_Change()
    Static BeenHere As Boolean
    If Not BeenHere Then
        BeenHere = True
        cCombo2.Change Combo2.Text
        BeenHere = False
    End If
End Sub

It would be more practical to create a collection of this type of object and simply indicate the name of the ComboBox we want to use, in other words the class itself would take care of looking for it's appropriate object (ComboBox), if it exists, if not it will generate an error. Let's look at the code for the class/collection and how it would be used in the form. One thing: the type of object in the collection will be the same as we previously wrote. That way we can use it as a stand-alone or collection.

' Code from the Collection class ...
Option Explicit

Dim colCombos As New Collection

Public Sub AddCombo(ByVal NewCombo As ComboBox)
   Dim tCombo As New cSearchCbo
   Dim theIndex As String
 
   On Local Error Resume Next
   ' Add a new ComboBox
   Set tCombo.Combo = NewCombo
   With NewCombo
       theIndex = Format$(.Index, "000")
       ' If it's not part of an array, you'll
       ' get an error
       If Err Then
           'If not, assign a default
           theIndex = "000"
       End If
               Err = 0
       colCombos.Add tCombo, .Name & theIndex
   End With
   ' If we get an error, it's already in there
 
   Set tCombo = Nothing
   Err = 0
End Sub

Public Function Item(ByVal Index As ComboBox) As cSearchCbo
   ' This procedure must be marked as Procedure ID "Default" in the
   'Object browser (VB5 Only)
   Dim theIndex As String
 
   On Local Error Resume Next
 
   With Index
      theIndex = Format$(.Index, "000")
      ' If it's not part of an array, you'll
      ' get an error
      If Err Then
          'If not, assign a default
          theIndex = "000"
      End If
      Err = 0
      Set Item = colCombos(.Name & theIndex)
      End With
 
   If Err Then
       ' Doesn't exist
       Err.Raise Number:=vbObjectError + 1000, _
                 Source:="cCombos", _
                 Description:="Element not found"
   End If
 
End Function

Code from the Form:

Option Explicit

'The Class/Collection
Dim Combos As cCombos

Private Sub Form_Load()
   Set Combos = New cCombos
   Combos.AddCombo Combo1
   Combos.AddCombo Combo2
End Sub

Private Sub Form_Unload(Cancel As Integer)
   Set Combos = Nothing
   Set Form1 = Nothing
End Sub
 

Private Sub Combo2_Change()
   Static BeenHere As Boolean
   If Not BeenHere Then
      BeenHere = True
      With Combo2
          Combos(Combo2).Change .Text
      End With
      BeenHere = False
   End If
End Sub
Private Sub Combo1_Change()
   Static BeenHere As Boolean
   If Not BeenHere Then
      BeenHere = True
      With Combo1
          Combos(Combo1).Change .Text
      End With
      BeenHere = False
   End If
End Sub

Private Sub Combo2_KeyDown(KeyCode As Integer, Shift As Integer)
   Combos(Combo2).KeyDown KeyCode
End Sub
Private Sub Combo1_KeyDown(KeyCode As Integer, Shift As Integer)
   Combos(Combo1).KeyDown KeyCode
End Sub

Private Sub Combo2_KeyPress(KeyAscii As Integer)
   Combos(Combo2).KeyPress KeyAscii
End Sub
Private Sub Combo1_KeyPress(KeyAscii As Integer)
   Combos(Combo1).KeyPress KeyAscii
End Sub
 
 

As you can see, it's easier to use the code in the second example, although if you only have one ComboBox which needs this functionality, it's not necessary to use the collection class.

    I hope that despite the fact that this article might be a little too "tutorialistic" in style, that it helped you to understand Visual Basic classes in general. If there is sufficient reader interest I could write more practical articles on how to create simple classes and collections. I'm awaiting your comments.
 

 
 I'll see you around.
Guillermo
P.S.
If you're interested, here's the code for the examples. (In Spanish) objects.zip


About the Author

Copyright 1995-1998 VB Online. All rights reserved.