3. Named Arguments
Visual Basic lets you include the name of arguments when you call a procedure. This is most obvious in recorded code:
Selection.AutoFormat Format:=xlRangeAutoFormatSimple, Number:=True, Font _
:=True, Alignment:=True, Border:=True, Pattern:=True, Width:=True
The name before the :=
is the name of the argument and the item after it is the value of that
argument. This is handy if you want to use mostly default values; for
instance, the following code reformats a selection without adding
borders or changing column widths:
Selection.AutoFormat Format:=xlRangeAutoFormatSimple, Border:=False, Width:=False
You can do the same thing
without names by relying on the positions of the arguments instead. The
following line does exactly the same thing as the preceding one:
Selection.AutoFormat xlRangeAutoFormatSimple, , , , False, , False
I tend to omit named
arguments because I feel they are often too verbose and because the
next generation of Visual Basic (Visual Basic .NET) doesn't use them.
Feel free to disagree with me on this one, though. |
|
An approach that works better than named arguments
in my opinion is using Visual Basic's Auto Complete feature. That feature doesn't work with generic types of objects like Selection and ActiveSheet, so you must first get the specific type of object as shown in Figure 3.

4. Properties
Function procedures return a result and so can be used on the righthand side of an assignment:
x = CubeRoot(42)
But what if you want to put a procedure name on the lefthand side? That's what properties
do. Property procedures
can be assigned to or assigned from—they can appear on either side of =. For example, the following code defines a Name property for a module:
' Code in PublicProcedures module
Dim m_name As String
' Assign the name.
Public Property Let Name(arg As String)
m_name = arg
End Property
' Return the name
Public Property Get Name( ) As String
Name = m_name
End Property
Code outside the module can set or return the value from m_name by calling the Name property:
Sub TestProperties( )
PublicProcedures.Name = "Module name"
Debug.Print PublicProcedures.Name
End Sub
You could do something similar by just making m_name
a public variable, but properties allow you special control that you
don't get with that technique. For example, the following code makes
sure that Name is set only once:
Public Property Let Name(arg As String)
If arg <> "" And m_name = "" Then
m_name = arg
Else
MsgBox "Name is already set to: " & m_name
End If
End Property
You can make a property read-only
by not defining a Let procedure:
Const m_date = #6/5/2004#
' Read-only property (no Let procedure)
Public Property Get Created( )
Created = m_date
End Property
Properties can represent objects if they use Set instead of Let. For example, the following read/write property keeps track of a range of cells currently in use by the module:
' Object property (uses Set instead of Let)
Public Property Set CurrentRange(arg As Range)
Set m_range = arg
End Property
Public Property Get CurrentRange( ) As Range
Set CurrentRange = m_range
End Property
You can use an object property as part of a Set statement as shown here:
Set PublicProcedures.CurrentRange = Selection
Debug.Print PublicProcedures.CurrentRange.Address
All of the property samples I show here are part of a module. It is more common to find properties
defined in classes
. In those cases, you must first create an instance of an object from
the class before using the property. For example, if you created the
preceding properties in a class module named PublicClass, you'd use the following code to test them:
Sub TestObjectProperties( )
Dim obj As New PublicClass
' Read-write property.
obj.Name = "Module name"
Debug.Print obj.Name
' Read-only property
Debug.Print obj.Created
' Object property
Set obj.CurrentRange = Selection
Debug.Print obj.CurrentRange.Address
End Sub
5. Events
The last kind of procedure is special type of Sub called an event procedure. Event procedures
are where you write code that responds to things that happen in Excel,
such as the user opening a workbook, clicking on a button, or changing a
selection.
Events can exist only in classes, so it's easiest to see them by looking somewhere like the ThisWorkbook class shown in Figure 4.
To view the events
that Excel defines for a class:
Open the class module in a Code window.
Select an object from the Code window's object list.
Select
an event from the Code window's event list. Visual Basic inserts the
event definition for the selected event in the Code window.
The event definition is a Sub procedure that matches to the event's name and argument list. Some events, such as Open, don't have any arguments; others, such as SheetSelectionChange,
have several. Any code you add to an event definition is run whenever
that event occurs in Excel. You can see how this works by adding the
following event procedure to the ThisWorkbook class:
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, _
ByVal Target As Range)
MsgBox "Sheet: " & Sh.Name & " " & " Selected range: " & Target.Address
End Sub
The preceding code
displays the sheet name and range address any time you click on a new
cell in the Excel workbook. There's more on Excel's built-in events
later in this book. Right now, I'd like to tell you how to create your
own events.
There are two phases to creating your own events in a class:
Declare the event using the Event keyword.
Trigger the event using the RaiseEvent keyword.
Go back to the PublicClass example I've been using, and add the following lines shown in bold:
' Code in PublicClass class
' Class-level variables used by properties
Dim m_name As String
Const m_date = "6/5/2004"
Dim m_range As range
' Event declaration
Public Event RangeChange(rng As range)
' Assign the Name property
Public Property Let Name(arg As String)
If arg <> "" And m_name = "" Then
m_name = arg
Else
MsgBox "Name is already set to: " & m_name
End If
End Property
' Return the Name property
Public Property Get Name( ) As String
Name = m_name
End Property
' Read-only property (no Let procedure)
Public Property Get Created( )
Created = CDate(m_date)
End Property
' Object property (uses Set instead of Let)
Public Property Set CurrentRange(arg As range)
Set m_range = arg
' Trigger the event
RaiseEvent RangeChange(m_range)
End Property
Public Property Get CurrentRange( ) As range
Set CurrentRange = m_range
End Property
Now objects created from PublicClass will include a RangeChange event that occurs whenever the class's CurrentRange property is set. To use this event from another class, such as ThisWorkbook, you must:
Declare an object using the WithEvents keyword. That adds the object to the Code window's events list.
Create an instance of the object.
Add an event definition for the event.
Do something to trigger the event.
To see the new event at work, open the ThisWorkbook class in a Code window and make the following changes:
' Code in ThisWorkbook class
Dim WithEvents obj As PublicClass
' Respond to the RangeChange event.
Private Sub obj_RangeChange(rng As range)
' Display the new current range.
MsgBox "Current range: " & rng.Address
End Sub
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, _
ByVal Target As range)
'MsgBox "Sheet: " & Sh.Name & " " & " Selected range: " & Target.Address
' Create object if it has not already been created.
If TypeName(obj) = "Nothing" Then Set obj = New PublicClass
' Set the object's current range to trigger the event.
Set obj.CurrentRange = Target
End Sub
Now when you click on cells in the workbook, your code changes the CurrentRange property which triggers the RangeChange event and displays a message box with the current setting. It might be useful to set a breakpoint in Workbook_SheetSelectionChange and step through the code to see how the code executes.