Design-Drawing Home  
Drawing Program
ISSN 1441-5585

Search...

Home
Articles
Software Catalog
Book Store
About
Advertising
Newsletter

 

 

Advanced VBA Topics in Visio

Ken Getz and Mike Gilbert

Roll Your Own Objects
Class modules are one of the most exciting additions to VBA 5.0. (These modules were introduced in Visual Basic 4.0.) Using class modules, you can create your own objects. These objects can expose their own set of properties and methods, and you can create multiple instances of the object, if your application needs this functionality.

In the simplest possible case, the code below demonstrates a Student class, and the demonstration procedure creates two Student objects, sets their properties, and then calls a method of each. (Note that public variables in the class become the properties of the class, and public procedures become its methods.)

' From Student.CLS

Public FirstName As String
Public BirthDate As Date
Public Sub Speak()
MsgBox "My name is " & FirstName & _
" and I was born on " & BirthDate & "."
End Sub

' From TestClass.BAS

Sub WorkWithStudents()
Dim Student1 As New Student
Dim Student2 As New Student

With Student1
.FirstName = "Sue"
.BirthDate = #5/1/76#
End With

With Student2
.FirstName = "Tom"
.BirthDate = #4/12/65#
End With

Student1.Speak
Student2.Speak
End Sub

In the example, the variables Student1 and Student2 refer to two instances of the class module, and each maintains its own set of properties. Therefore, when you execute the Speak method of the class, each "student" can speak for him or herself.

Of course, this is a simple, silly example. Class modules have wide-ranging uses, limited only by your imagination. Their most important use comes into play when you combine them with Collection objects. For more information, and many examples, we recommend you take a look at "VBA Developer's Handbook" (OK, it's a blatant plug), which contains many examples of using class modules to solve various types of programming problems.

WAIT! If you're currently creating utility libraries as DLLs (written in C/C++/Pascal, perhaps), stop! Visual Basic 4.0 (and 5.0, of course) makes it simple to create ActiveX automation servers that can wrap up your DLL functionality, or even replace it. Then, you can call the functions exposed by the ActiveX server from any VBA host – all it requires is that your applications register the server using the Tools|References dialog. Whether you simply wrap a layer over your existing functionality, or replace it with new ActiveX servers, this is the way to go, and class modules in Visual Basic make it all possible. Just say no to Declare statements in VBA code! (You can't create these stand-alone ActiveX Automation servers in VBA, you'll need Visual Basic 4 or higher to manage this task.)

Properties Aren't Always So Simple
Sometimes, you may want to restrict a property so that it's read-only. Or perhaps you want to perform some action when a property gets set. Using public variables for properties, you can't do either of these. VBA provides Property Get and Property Let procedures, so you can run code when a property is retrieved or set, or both. The following code, a revised version of the original class module and its test procedure, demonstrates this behavior.

' From Student1.CLS

Public FirstName As String
Public LastName As String
Public BirthDate As Date
Private mstrMiddleName As String
Private mstrMI As String
Public Sub Speak()
MsgBox "My name is " & FirstName & _
" and I was born on " & BirthDate & "."
End Sub

Public Sub FormalSpeak()
MsgBox "My name is " & FullName & "."
End Sub

Property Get FullName() As String

' Retrieve the FullName property.
' This is a read-only property, of course.
' Note the missing Property Let procedure!

If Len(MI) > 0 Then
FullName = FirstName & " " & MI & ". " & LastName
Else
FullName = FirstName & " " & LastName
End If
End Property
Property Let MiddleName(pstrMiddleName As String)

' Store away the middle name.

mstrMiddleName = pstrMiddleName

' If the middle name was longer than
' a single character, store away the
' middle initial, as well.

If Len(pstrMiddleName) > 0 Then
mstrMI = Left$(pstrMiddleName, 1)
End If
End Property

Property Get MiddleName() As String

' Return the middle name.

MiddleName = mstrMiddleName
End Property

Property Get MI() As String

' Another read-only property.

MI = mstrMI
End Property

' From TestClass1.BAS

Sub WorkWithStudents1()
Dim Student1 As New Student
Dim Student2 As New Student

With Student1
.FirstName = "Sue"
.MiddleName = "Ellen"
.LastName = "Smith"
.BirthDate = #5/1/76#
End With

With Student2
.FirstName = "Tom"
.LastName = "Powers"
.BirthDate = #4/12/65#
End With

Student2.FormalSpeak
Student1.FormalSpeak
End Sub

Collectors' Items
If you've programmed in just about any language, you've come across the humble array. This data structure allows you to group a number of items of the same data type into a single variable, indexed by their position within the variable. This data structure, in Basic, is somewhat limiting, because:

  • You must either specify the size of the array, once and for all, when you create it, or
  • You can create a dynamic array, but resizing the array requires a massive move of all the elements

Basically, an array is a static data structure. If you know ahead of time how many elements you'll need, or the number of elements is small, arrays are fine.

If you need a dynamic data structure, the Collection is your answer. This data structure allows you to add elements at will. The elements can be of any data type, and you can add, remove, and retrieve any item that you need.

To work with collections, you'll need to first create the collection itself:

Dim colNames As New Collection

By using the New keyword, you've instructed VBA to create a new collection object for you. Now you're all set to use the Add, Remove, and Item methods of the collection object, allowing you to add, remove, and retrieve items in the collection.

Once you've got a collection with items in it, you can use the For Each…Next syntax to loop through the items in the collection. Using this syntax, you needn't know how many items there are – just keep looping until you run out.

Let's modify the previous class module example one more time, using a collection to store Student objects. Once you're done entering the students, the code will loop through the collection, retrieving the Name property for each student, in turn.

Sub UseCollection()
Dim colStudents As New Collection
Dim strName As String
Dim oStudent As Student

' Retrieve names until you get tired of it.

Do
strName = InputBox("Enter a name:")
If Len(strName) > 0 Then

' If you entered a name, create
' a new student, and add him/her
' to the collection.

Set oStudent = New Student
oStudent.FirstName = strName
colStudents.Add oStudent
End If
Loop While Len(strName) > 0

' Now loop through all the students, "speaking"
' the name.

For Each oStudent In colStudents
oStudent.Speak
Next oStudent

' Although the following two lines aren't
' necessary, they're a good idea.

Set oStudent = Nothing
Set colStudents = Nothing
End Sub

Passing Parameters Your Way
VBA 5.0 adds some useful new techniques for passing parameters to procedures. The following sections will introduce each of these new methods for passing parameters to procedures.

Named Parameters
Think WordBasic. Think procedures that accept 15, 20, perhaps even 25 parameters. Think of calling procedures like this:

SomeWordProcedure ,,,,,,,,,,,,1,,,3,,5

when all you wanted to do was set three of the umpteen possible parameters.

Named parameters (introduced in WordBasic, for obvious reasons, and only recently incorporated into VBA) allow you to specify only the parameters you want to specify, assuming the default values for all the rest. (See the next section, "Optional Parameters", to find out how you can create your own optional parameters.) If you specify the name for the parameters you want to send, then you needn't include all the comma placeholders:

SomeWordProcedure Widgets:=1, Foogles:=3, Wombats:=5

Use the ":=" combination to indicate that you're supplying a named parameter, and you're all set. Note that once you supply a named parameter, you must supply the names for all subsequent parameters – by supplying a name at all, you've turned off VBA's ability to use the position of the parameters.

Optional Parameters
To make the procedures you write as useful as possible in as many circumstances as possible, you may want to use optional parameters. If you do, you'll also want to supply default values for the optional parameters.

To do this, use the Optional keyword in the formal declaration of your procedure. You can specify a default value in the declaration, or, if you use Variant parameters, you can use the IsMissing function in the body of the procedure to see if the caller passed a value for the parameter.

For example, the following procedure accepts two parameters, a first name and a birthdate. If you don't specify the first name, the code assumes you want to use "Sue". If you don't specify a birthdate, it assumes you want to use the current date.

Sub TestOptional(Optional FirstName As String = "Sue", _
Optional BirthDate As Variant)
Dim oStudent As New Student

If IsMissing(BirthDate) Then BirthDate = Date
With oStudent
.FirstName = FirstName
.BirthDate = BirthDate
.Speak
End With
End Sub

Of course, you can combine named parameters with optional parameters. You could call TestOptional like this:

TestOptional BirthDate:=#5/16/96#

to specify just the birthdate, for example.

ParamArray
VBA, for some reason, doesn’t include a procedure to calculate the minimum value of a list of numbers. Suppose you'd like to write such a function, allowing it to accept 1, 2, or more parameters. You need some way to take a list of parameters, and treat them as a group.

The ParamArray keyword allows you to do this. The following function accepts a list of values, and returns the minimum value in that list.

Function Minimum(ParamArray Items() As Variant) AS Variant
Dim varMin As Variant
Dim intI As Integer

' UBound returns -1 if the array has no items
' in it. Use that to make sure the caller
' passed some items at all.

If UBound(Items) > 0 Then
varMin = Items(LBound(Items))
For intI = LBound(Items) To UBound(Items)
If Items(intI) < varMin Then
varMin = Items(intI)
End If
Next intI
End If
Minimum = varMin
End Function

You might call Minimum like this:

VarMin = Minimum(1, 2, 3, 4, 5, -1, 12, 65)

No matter how many items you pass, VBA converts them into an array and hands them to Minimum in the Items parameter. The code can then work with the array as if you'd put the items in an array before calling Minimum.

Note: You can't have an optional ParamArray parameter, and once you've declared a parameter as being ParamArray, you can't have any subsequent parameters. (How would VBA know when the ParamArray list stopped, and the next parameter started?)

Part I

Ken Getz and Mike Gilbert

Also in this series:

VBA and Visio

Visio and the VBA IDE

Microsoft Forms

Advanced VBA

VBA Developer's Handbook
VBA Developer's Handbook by Ken Getz and Mike Gilbert

 
Rate this article...
Hmmm  OK  Good  Yes! Brilliant
Your a friend about this article.

Copyright © 1998-2007 DBM & others | Disclaimer | Privacy | Re-publication | Trademarks | Webmaster | Home