Professional Documents
Culture Documents
CHAPTER 2.
When working with both EXCEL sheets and the VBE, it is sometimes convenient to press the middle button at the top right of each of these windows
and to tile the two one above the other by moving them and adjusting the
borders. Double clicking at the top bar of one of the windows expands (or
contracts) the window.
Three useful windows which can be included in the VBE display are:
Locals Window shows how all the variables in procedures change during
runtime
Immediate Window commands entered here are immediately executed
Watch Window allows you to monitor specific variables during execution.
These windows can be docked into your VBE window from the View menu.
If it becomes undocked, it can be redocked by double clicking the bar at the
top of the window.
2.2
2.2.1
Variables
Variable names begin with a letter (uppercase or lowercase) and continue with
letters or numbers or underscore . Variable names are not case sensitive.
Each variable has a type. Some of the principal types are Integer, Long, Single,
Double, Boolean, String, Variant. (Long is an integer type, Double is a
real number type with double precision, Boolean can take values True, False).
The Variant type is a sort of hold-all, and all the other types can be accommodated in it. The type of a variable need not be declared (unless
CHAPTER 2.
Option Explicit is set - see below), and if the type is not declared, it is
automatically of type Variant. The Variant type sets aside more memory
space than other types. At some stage, it is converted to house the actual
variable (of whatever type.) A useful application of Variant types is when
data is requested from a user which could be text or numeric. Putting it into
a Variant typed variable allows either format.
The Declarations (first section) of a module can contain Option statements
and certain variable declarations. A very useful option is
Option Explicit
This makes it compulsory for a variable to be either an argument of a function or sub, a function name or to be declared in a Dim dimension statement.
(Note that a function name is automatically declared (without a Dim statement), with type as stated at the end of the function declaration line and
the arguments are also automatically declared but a sub name is NOT.) The
dimension statement is of the form
Dim Str,Int,Rl
where Str,Int,Rl are variable names the types of the variables are not declared in this form so the three variables are of Variant type. Alternatively
Dim Str As String, Int As Integer, Dbl As Double, Var
types all the variables except for Var, which is then of Variant type by default.
Dbl is a double precision real number.
Note: You cannot use
2.2.2
The procedure QMinus below calculates the solution of the quadratic equation
Ax2 + Bx + C = 0
given by
B 2 4AC
2A
for the case A 6= 0, B 2 4AC 0. Very little error checking is done. QPlus
below calculates the other root. A more complete quadratic equation solver
will be the subject of a later exercise.
x=
QMinus, the function name, is assigned a value and this is the return value of
the function. If you use the function, (for example =QMinus(1,2,3) in an
Excel cell), then the final value of the variable QMinus is the value returned.
CHAPTER 2.
Function
Dim
Delta As Double
Delta = B*B4*A*C
If Delta >= 0 Then QPlus = QMinus(A,B,C) + B/A
Else QMinus = 999999
End Function
To test the function, tile EXCEL and VBE and enter in the Immediate Window
Range("C1") = QMinus(1,-3,2)
Range("D1") = QPlus(1,-3,2)
Debug.Print QPlus(1,-3,2)
MsgBox QMinus(1,-3,2)
Enter in the EXCEL sheet
=QMinus(1,-3,2) in C2
=QPlus(1,-3,2) in D2
If there are errors, the program will stop. Try to correct them and then
press the button with a triangle in the VBE to continue or the button with a
square to stop. You can stop before a line by clicking in the left margin next
to the line and running the function. A dot appears in the margin next to
the stoppage line. You can watch the variables at that time by looking in the
Locals window or setting a watch in the Watch window. Click the triangle
to run the function in which the cursor is sitting, or to continue. You can
run the function step by step by successively pressing F8. See the section on
Debugging for further information.
To exit from a function before the last statement use:
Exit Function
The words Public or Private before the word Function in the declaration
indicates, in the case of Public, that the function is usable outside the code
module and in the case of Public that it is not. The default is Public.
2.2.3
To access and change the WorkBook cells, we must use the object-oriented
aspects of VBA. This can be done by sub procedures. Function procedures
have limited ability to change the spreadsheet.
"Value" is a string
End Sub
More generally, there can be more than one Dim statement and more than
one line assigning to variables and evaluating functions and subs and using
methods and setting properties.
Remember that MySub is not available immediately as a variable, in contrast
to the case of functions.
For examples of manipulating ranges and cells see the forthcoming section on
working with ranges and cells in VBA.
To exit from a sub before the last statement:
Exit Sub
to call or run a sub from within another sub use:
MySub 2.34,"fine"
or
MySub A:=2.34,B:="fine"
There are other ways of calling subs. There is a method using Call but this
is undesirable. Sometimes subs (or methods) must be run using a bracket
notation for the arguments. This is discussed further in the section on Objects
below.
The sub can be declared as Public or Private as for functions, with default
Public.
2.2.4
Built-In functions
CHAPTER 2.
To find a list of built-in VBA functions. Click Help, the Index tab
and type Math in the box. Then press Enter and click on Math Functions.
There is also an item Derived Math Functions, but these must be entered
by the user as composites of the standard functions - they do not exist on
their own. Another route:
Help|Contents|VisualBasic Language References|Groups|Maths Functions.
Using EXCEL Functions in VBA. The correct way is to prefix the
function by
Application.WorksheetFunction
and then use the EXCEL function name. It will also work if WorksheetFunction
is omitted or if Application is replaced by Excel. Such a prefix is lengthy.
If you need to use it several times in a module, you can put the following
in the Declarations section:
Dim WSF as WorksheetFunction
In any function which uses EXCEL functions, you can put the statement
Set WSF = Application.WorksheetFunction
Then, for example,
WSF.cosh(2)
will give you the value of cosh 2. If you get some error, check that the
function you use is actually allowable for use in VBA.
To enter a Formula into a Cell from VBA
It is often necessary to do calculations on the worksheet rather than in
VBA. An example of this is in the use of Solver routines, which require
its inputs to be calculated by EXCEL formulae evaluated in cells.
To enter a formula from VBA which will output to a single cell, use the
following format:
Activesheet.Range("A1").Formula = "=NormSInv(Rand())
The formula is evaluated and the result placed in cell A1.
To enter a formula from VBA which will output an array, use the following
format:
Activesheet.Range("A1:A5").FormulaArray = "=MMult(C1:G5,I1:I5)"
The formula is evaluated and the result placed in range A1:A5.
2.2.5
Looping
2.2.6
Conditional Statements
The following illustrate the multiline If-Then-Else statement, the single line
version and the Select Case statement.
Multiline If-Then-Else
Dim Number, Digits, MyString
Number = 53
Initialize variable.
If Number < 10 Then
Digits = 1
ElseIf Number < 100 Then
Condition evaluates to True so the next statement is executed.
Digits = 2
Else
Digits = 3
End If
Single Line If-Then-Else
Assign a value using the single-line form of syntax.
If Digits = 1 Then MyStr = "One"
OR
If Digits = 1 Then MyStr = "One" Else MyStr = "More than one"
Select Case
10
CHAPTER 2.
Dim Number
Number = 8
Initialize variable
Select Case Number
Evaluate Number
Case 1 To 5
Number between 1
Debug.Print "Between 1 and 5"
The following is
Case 6, 7, 8
Number between 6
Debug.Print "Between 6 and 8"
Case 9
Debug.Print "Number is 9"
Case Else
Other values
Debug.Print "Not between 1 and
End Select
and 5, inclusive
the only Case clause that evaluates to True.
and 8
9"
Note: In the phrase Select Case Number we could replace Number by any
variable or expression that evaluates to a number or a character string.
2.2.7
A function returns a value, and this can be used in a cell to assign a value,
e.g. =f(q). You may want to return several values from a function or sub for
use in another function or sub.
A function declaration is of the form
Function functionname(var1 As Integer, var2, var3() As Single,
Optional var4 As Double) As Boolean
If the type is not declared, then a variable is of type Variant.
functionname, var1, var2, var3, var4 are all available for use in the
body of the function, and cannot be dimensioned with Dim or ReDim.
Variable var3() is an array argument which takes its dimension from the
input array at runtime - see the section on arrays later.
functionname can be assigned a value in a function - in this case a
Boolean value. If we had omitted As Boolean then functionname would
have been of type variant. See below for discussion of optional variables.
If we have a sub declaration, then it must be of the form:
11
tt()
a As Double, b As Double, c As Double
0
0
0
tf(a,b)
Sub
12
CHAPTER 2.
2.2.8
Optional Arguments
In the functions we have been writing, all arguments are compulsory, that is,
they must be supplied. It is possible to make some arguments optional by
using declarations of the form:
Function Opt(intNumber As Integer, Optional strWord As String)
Then legal calls are of the form var=Opt(1,"go") and var=Opt(1). If Opt is
a sub, then use
Sub Opt(intNumber As Integer, Optional strWord As String)
Opt intNumber:= 1, strWord:= "go"
Opt intNumber:= 1
All compulsory arguments should go before the optional ones, to enable one
to use the Opt(1) form, since the called arguments must appear in order, and
it may not be clear what is omitted.
To test whether an optional argument has been used, the IsMissing boolean
function can be used in the function or sub provided that the variable
has Variant type:
If IsMissing(strWord) Then GoTo Stop
If the variable does not have type Variant then one can assign a default value
to the variable and then check in the procedure whether the variable still has
the default, in which case it is missing:
Function Opt2(intN As Integer, Optional strW As String = "Default1")
If strW="Default1" Then GoTo Stop
It is also possible to have as arguments a variable number of parameters by
using the ParamArray argument. See below.
Parameter Arrays as Arguments - Passing a Variable Number of
Arguments
This section requires arrays and should be read after the later section on
arrays, but the material is relevant to this section. A parameter array can
be used to pass an array of arguments to a procedure. One does not have to
know the number of elements in the array when you define the procedure.
13
One uses the ParamArray keyword to denote a parameter array. The array
must be declared as an array of type Variant, and it must be the last argument
in the procedure definition.
The following example shows how one might define a procedure with a parameter array.
Sub AnyNumberArgs(strName As String, ParamArray intScores() As
Variant)
Dim i As Integer
Debug.Print strName; "
Scores"
Use UBound function to determine upper limit of array.
For i = 0 To UBound(intScores())
Debug.Print "
"; intScores(i)
Next
End Sub
The following examples show how you can call this procedure.
AnyNumberArgs "Jamie", 10, 26, 32, 15, 22, 24, 16
AnyNumberArgs "Kelly", "High", "Low", "Average", "High"
Note: Another way of passing a variable length argument list is to declare say
the last argument of a function or sub as a Variant. Then feed the arguments
into the variable by feeding in an array. One can then use the above procedure
with Ubound to find out how many arguments have been passed and access
them as above. This has many advantages as a range object can be passed
to the variant and its values are then available to the function. However, see
the function maxRange below for another method.
Further Examples
The function maximum illustrates the writing of a program with an arbitrary
number of variables. The function hypotenuse avoids squaring large numbers
and then taking their square root, thereby reducing the possible sizes of the
inputs. The function maxRange inputs a range of cells and finds the number
of rows and columns in the input. This is useful for inputting data.
Function maximum(ParamArray inputs() As Variant)
Dim i As Integer
maximum = inputs(0)
14
CHAPTER 2.
For i = 1 To UBound(inputs())
If inputs(i) > maximum Then maximum = inputs(i)
Next
End Function
Function minimum(ParamArray inputs() As Variant)
Dim i As Integer
minimum = inputs(0)
For i = 1 To UBound(inputs())
If inputs(i) < minimum Then minimum = inputs(i)
Next
End Function
Function hypotenuse(x As Double, y As Double) As Double
Dim temp As Double
If x > y Then
temp = y / x
hypotenuse = x * Sqr(1 + temp ^ 2)
Else
temp = x / y
hypotenuse = y * Sqr(1 + temp ^ 2)
End If
End Function
Function maxRange(strRange As String) As Double
Dim ran As Range, i As Integer, j As Integer
Set ran = Range(strRange)
maxRange = ran.Cells(1, 1)
For i = 1 To ran.Rows.Count
For j = 1 To ran.Columns.Count
If ran.Cells(i, j) > maxRange Then maxRange = ran.Cells(i, j)
Next j
Next i
End Function
Sub
Dim
m =
h =
r =
End
tstmax()
m As Double, h As Double, r As Double
maximum(1, 2, 3, Application.Pi())
hypotenuse(311111111111, 411111111111)
maxRange("A1:E2")
Sub
15
We often have to pass a function (or sub) to another function (or sub). For
example, in Newtons method, we need to tell the function implementing
the method which function to use for in order to find the root and what its
derivative is. We would like to pass this as an argument. There is a VBA
function Run which takes as first argument the string that is the function
name and as subsequent arguments the arguments of the function to be run.
The output is the value that would have resulted had we run the function in
the normal way. We give an example.
tst()
Calculates the square root of 3 by Newtons Method
d As Double
newt("qd", "qdder", 100, 3)
Sub
16
CHAPTER 2.
2.3
The following indicate how to refer to Range and Cells objects and their
properties:
Object
Application
Description
The entire EXCEL spreadsheet that is currently open
The default value (when omitted) is the current workbook
Sheets("Sheet2")
WorkSheet named Sheet2 of current application
The default value (when omitted) is the current active sheet
Range("A1:B3")
The cells in this range
Range("A1").Name
e.g. Range("A1").Name = "X"
Range("A1").Formula
e.g. Range("A1").Formula = "=C1"
Range("A1").Value
e.g. Range("A1").Value = 1.2
(Value may be omitted after Range, as it is the default)
Range("A1").Font.Name
= "Times New Roman"
Range("A1").Font.Size
= 11
Range("A1").Font.Fontstyle
= "Bold"
Range("A1").Font.Superscript
= True
Range("A1").Font.Subscript
= False
Range("A1").Font.ColorIndex
= 4
1=black;2=white;3;4;5=R;G;B (Look up ColorIndex in VBE Help)
Range("A1").Interior.ColorIndex
=5 ColorIndex is a property of Interior
Range("A1").Interior.Pattern
See VBE Help under Pattern
Range("A1").Interior.PatternColorIndex
Range("A1").Borders(xlEdgeRight)
See Help
Range("A1").Borders.LineStyle
= xlContinuous
Range("A1").Borders.Weight
= xlThick
Range("A1").Borders.ColorIndex
= 3
With Range("A1").Borders
Way to avoid repeating prefixes
.LineStyle = xlContinuous
.Weight = xlThick
.ColorIndex = 3
var = .ColorIndex
Assigns the value of ColorIndex to a variable
End With
Range("B2:C5").BorderAround weight:=xlMedium
Cells(i,j)
The row i, column j cell of the active worksheet
Note that the indices are 1-based
Cells(3,2)
Cell B3
Range("B2").Cells(2,3)
D3
Range("B3:C10").Cells(i,j)
Cell (i,j) relative to B3 as (1,1)
Range(Cells(2,3),Cells(4,5))
17
Tile EXCEL and the VBE and enter variations of the above property settings
in the Immediate Window.
The Cells Property and Looping through Cells
A way of referring to cells and ranges is with the Cells property. See examples
in the previous list. This may be used, for example, to loop through a range
of cells:
For i = 1 To 10
For j = 1 To 12
matrix(i,j) = Range("B2").Cells(i,j).Value
Next
Next
Alternatively:
For i = 1 To 10
For j = 1 To 12
matrix(i,j) = Range(Chr(Asc("B") - 1 + j) & i).Value
Next
Next
where Chr() converts a positive integer to the character with that number in
the ASCII character set and Asc() converts a character to its number in the
ASCII character set.
The property Value of the Range object is the default property. Thus Range("A1").Value
and Range("A1") both return the Value property value.
To get some idea on how to do spreadsheet tasks in VBA, you can do the
process in EXCEL while recording the code Excel uses in a module. The code
is almost always cumbersome and NEEDS MUCH EDITING to get it concise.
In EXCEL, use the menu items in Developer | Code.
Enter a name for the Macro (Subroutine), click OK and do your tasks.
Stop Recording.
Go to the VBE and look at the modules. One of them will have the code
of your tasks.
To view all the colours referenced by ColorIndex, run the following sub,
after changing Sheet3 to the sheet that you would like to use:
18
CHAPTER 2.
Sub colors()
Dim i As Integer, j As Integer
With Sheets("Sheet3")
With Range("G5")
.Value = "Colorindex"
.Font.fontstyle = "Bold"
.Columns.AutoFit
.Interior.ColorIndex = 15
End With
For j = 1 To 20
.Cells(j, 1).Interior.ColorIndex = j
Next For j = 1 To 20
.Cells(j, 3).Interior.ColorIndex = j + 20
Next
On Error GoTo endproc
For j = 1 To 20
.Cells(j, 5).Interior.ColorIndex = j + 40
Next
End With
endproc:
End Sub
The following sub draws a border around a range selected and colours it with
colour number index.
Sub colourborderrange(index As Integer)
With Selection
.BorderAround Weight:=xlMedium, LineStyle:=xlContinuous
.Interior.ColorIndex = index
End With
End Sub
With ... End With enables one to avoid repetition of parts of a statement
To run this, select a range in EXCEL and enter in the Immediate Window:
colourborderrange 5
Alternatively, we could replace the first two lines by
Sub colourborderrange(index As Integer, strRng As String)
With Range(strRng)
19
which does the same for the range which is the contents of strRng (such as
"B2:C5") instead of a selected range.
2.4
20
CHAPTER 2.
The function
ubound(dArray, 2)
above yields the value in N. The function call
lbound(iArray2, 3)
has value 8. For a dynamic array, we can use
Redim dArray(ubound(iArray2,2))
Passing Arrays to Other Subs
The best way usually is to use an extension of the following code fragment:
Sub CallingSub ()
Dim e() as Double
Redim e(7)
CalledSub e
e() is here the previous array e(7) after processing by CalledSub.
The values have been stored in d() (hence in e) since the variable
d is called by reference in CalledSub.
End Sub
Sub CalledSub (d() as Double)
Dim i As Integer
For i = 1 to Ubound(d,1)
Do something with array d()
Next
End Sub
Assigning Values to Arrays
We consider two cases:
The object to which values are assigned is NOT a Range in the
Spreadsheet
It is then best to assign values component by component, although under
special circumstances, it is possible to use a block method (see below).
The following is RECOMMENDED:
Sub imprt(A() As Double)
21
Dim A As Variant
A = Range("A1:B2").Value
If you wish to assign an array directly, do not dimension A or use A(1)= 2
etc before assigning the array to A. Also, A must be of type Variant if you
assign worksheet values in a block of cells directly to A.
22
CHAPTER 2.
23
Next i
Range("A1:"
Range("B1:"
Range("C1:"
Range("D1:"
Range("E1:"
&
&
&
&
&
"A"
"B"
"C"
"D"
"E"
&
&
&
&
&
N).Value
N).Value
N).Value
N).Value
N).Value
=
=
=
=
=
rd
t
w
x
u
End Sub
We could equally have done the output using cells(i,j) and a loop.
We could have just used one-dimensional arrays x(N) and so on and in the
final statements writing to a range we could have then used
Range("A1:" \& "A" \& N).Value =Application.Transpose(rd)
and so on.
To enter an Array Formula from VBA
To enter a formula into a cell from VBA which will output an array, use the
following format:
Activesheet.Range("A1:A5").FormulaArray =
"=Application.MMult("C1:G5","I1:I5")"
The formula is evaluated and the result placed in range A1:A5.
Using a 1-dimensional array-valued VBA function in EXCEL cells:
When a 1-dimensional array (vector) occurs in a function or sub, it is ALWAYS regarded as a row vector when written to the spreadsheet.
Even if you transpose (Application.Transpose(v)) the vector v and assign
it to the function name and then use the function in a spreadsheet, it will
output a row vector.
To enter a 3-vector which is the output of function f(q) into your spreadsheet,
select a 1 3 set of cells, enter =f(q) and (simultaneously) press
Ctrl-Shift-Enter
To enter it as a column, select the 3 1 column and enter
=TRANSPOSE(f(q))
and then
Ctrl-Shift-Enter
24
CHAPTER 2.
Sub squared()
Dim B(1 To 2, 1 To 2) As Double
B(1, 1) = 1
B(1, 2) = 2
B(2, 1) = 3
B(2, 2) = 4
square B
Range("G1:H2") = B
End Sub
Sub square(A() As Double)
Dim i As Integer, j As Integer
Range("A1:B2").Value = A
Range("D1:E2").Value=Application.WorksheetFunction.MMult _
(Range("A1:B2"), Range("A1:B2"))
For i = 1 To UBound(A, 1)
For j = 1 To UBound(A, 2)
A(i, j) = Range("D1").Cells(i, j).Value
Next
Next
End Sub
2.5
Further VBA
Contents: Using Help, Communication with the user, Input from the user,
Constants, User-defined Data Types, Timing Code, Running Subs from buttons,
25
26
CHAPTER 2.
Type EmployeeRecord
ID As Integer
Name As String * 20
Address As String * 30
Phone As Long
HireDate As Date
End Type
Sub CreateRecord()
Dim MyRecord As EmployeeRecord
MyRecord.ID = 12003
MyRecord.Name = "Bob"
End Sub
Declare variable.
Assignment to EmployeeRecord variable
must occur in a procedure.
Assign a value to an element.
Timing Code
Use the following to time the execution of a block of code:
StartTime = timer
(code)
EndTime = timer
TotalTime = StartTime - EndTime
Range("A1").value = TotalTime
This places into cell A1 the time taken in seconds to execute the code.
Running subroutines from a Button
This method uses a button on the Forms toolbox.
Activate a worksheet
Go to Developer | Controls | Insert, click the Button on the Forms section
and them click a cell in the Worksheet. The button appears there, and a
box appears asking you to assign a macro. Give the name of one of the
subroutines you have written in your code modules.
Click on another cell. Then click your button. The macro will run.
To change the button caption, right click on the button, highlight the caption with left button and change it.
27
Right click on the border of the button. Choosing Assign Macro will allow
you to change the macro. Choosing Format Control will allow you to format
some aspects of the button. Resizing can be accomplished by using the size
handles.
Subroutine with Arguments
You must insert the button from the Control Toolbox. Do so. Go into
Design Mode by making sure the toolbar button with the blue triangle is
clicked. Double click the button. A code window appears with a subroutine
which runs whenever the button is left - clicked. In the subroutine enter
YourSub arg1:= . . . , arg2:= . . .
Click the Properties button of the Control Toolbox. Change the Caption
property to your desired caption. Click the blue triangle button on the toolbar if necessary to turn design mode off. Click your button - the subroutine
will run.
Setting a Password
You can prevent others from expanding your workbooks name by setting
a password.
Go to the VBE. Go to menu item Tools | VBAProject Properties, and then
to the Protection tab. Set the password and confirm it. Press OK and
save the project (say, from the File menu). To load it in a new instance of
EXCEL and to be able to expand the project in the VBE you will need to
enter the password.
Having entered the password, you can remove the protection by using the
same protection tab and deleting the password and repetition.
Creating an Add-In
One can change any workbook into an Add-In. Any code will not be available for alteration and the worksheets of the Add-In can never become
active. The Code of the Add-In can, however, write to its own worksheets,
and these changes can be saved. The subs and functions of the Add-In
do not appear on the available list of subs and functions. These can be
run from other open workbooks also from forms and menus in these other
workbooks. We will not go into all this, but merely give a way of saving a
workbook as an Add-In. When it is loaded in the usual way via the Tools
| Add-Ins menu, the functions and subs can be used. We will only discuss
briefly a method for saving changes. Further information can be found on
the Microsoft website.
To change your workbook into an Add-In while it is open, go to the File |
Save As menu, go to the drop-down menu at the bottom marked Save as type
and go down to find Microsoft Excel Add-In (*.xla). Choose this and
28
CHAPTER 2.
save. The file is saved as an .xla file. This can be loaded as an Add-In
from the Tools menu in the usual way. You can then use the functions and
subs, so document these beforehand.
To delete the Add-In, go to the directory in which it is housed and change
the name or delete it. When you go into Excel, try to load the Add-In from
the menu. It will give you the opportunity of deleting it from the Add-In
list.
To delete the Add-In from your project without deleting it totally as above,
use the Intermediate window with code like
Workbooks("AddInName.xla").Close
If you wish to use the sheets of the Add-In you should use code like
ThisWorkbook.Sheets("Sheet2").Range("A1:B5").Clear
You can save changes by entering in the BeforeClose event code:
ThisWorkbook.Save
You can also use a dialog box in this code to leave it to the user to decide
whether to save or not.
2.6
Debugging
2.6. DEBUGGING
29
Locals window or setting a watch (see below). Click the triangle to run the
function in which the cursor is sitting, or to continue.
You can run the function step by step by first placing the cursor in the
function code and then successively pressing F8.
To look only at a few variables (not all) you can use the Watch window
and set the variables you want to see. To set them, go to Debug|Add watch
(while the cursor is in the desired routine.) You can then set breakpoints and
look at only the watched variables at these points.
To run a sub that has an argument do so from the Immediate window
(which can be made visible from the View menu). You would enter in the
Immediate window something like
sbr arg1:=2,arg2:=3
A useful command to add to a routine when debugging it is
Debug.Print variablename
which prints the value of variablename (when this statement is reached) in
the Immediate window.
To run a function named fun with, for example, a numerical argument v,
either call it from a specially written sub, or set breakpoints and enter in the
Immediate window something like :
a=fun(1.5)
Debug.Print a
or
Debug.Print fun(1.5)
2.6.1
A facility distributed by Matlab allows EXCEL to export data from the spreadsheet or VBA to Matlab, to execute Matlab programs and to import data from
Matrlab into EXCEL. The linking functions can be called either from the spreadsheet or from VBA.
Matlab must be installed. ExcelLink must first be available from Matlab and
installed. We will assume that this has been done.
Ensure that the link is loaded as an Add-In. Exclink.xla is an Add-In file
which is usually in the ToolBox subdirectory of the main Matlab directory.
30
CHAPTER 2.
In the Tools | Add-Ins menu make sure that there is an Excel Link option, and
check the check box. If it is not there, use the browse button to find it in the
above directory and load it and check the box. There will be some additional
buttons on the upper toolbar such as GetMatrix. Press one to make sure that
Matlab is running and if not click the buttons to ensure that it is. If you
are running link routines in VBA, you need also to switch to the VBE and
in Tools | References check the Excel Link box. The latter can only be done
when Matlab is running.
We will deal only with writing the routines in VBA. We will list a program in
VBA which illustrates most of the features and then comment on the code.
Only one- and two-dimensional numeric arrays, and one-dimensional character arrays (which are just the same as character strings can be transferred
to EXCEL. In addition, two-dimensional cell arrays whose elements are all
character strings may be transferred.
Sub ExLinkTrial()
Dim i As Integer, j As Integer, NewSheet As Object
Dim C1(2, 2) As Double, D(2, 2) As Double
Set NewSheet = Sheets.Add(Type:=xlWorksheet)
NewSheet.Name = "Scratch"
For i = 1 To 5
For j = 1 To 4
Sheets("Scratch").Range("A1").Cells(i, j) = i * j
Next
Next
For i = 1 To 4
Sheets("Scratch").Range("F1:F4").Cells(i, 1) = i
Next
Sheets("Scratch").Range("F1:F4").Name = "y"
For i = 1 To 2
For j = 1 To 2
C1(i, j) = i * j
Next
Next
MLOpen
MLPutMatrix "AMat", Sheets("Scratch").Range("A1:D5")
MLPutMatrix "y", Sheets("Scratch").Range("F1:F4")
2.6. DEBUGGING
31
MLEvalString "SDE2"
MLEvalString "y=AMat*y;z=1"
MLGetMatrix "AMat", "Scratch!H1:K5"
MatlabRequest
MLGetMatrix "y", "Scratch!M1:M4"
MatlabRequest
MLPutVar "C1", C
MLGetVar "C1", D
Sheets("Scratch").Range("A7:B8").Value = D
MLClose
Application.DisplayAlerts = False
Sheets("Scratch").Delete
Application.DisplayAlerts = True
End Sub
The program first creates a new sheet in the workbook to do input-output
from a worksheet. Input-output from Matlab can also be done directly to VBA
variables by using MLPutVar and MLGetVar as illustrated in the program.
The program then writes some data to the new sheet, sends it to Matlab, runs
a Matlab script file, executes Matlab commands to manipulate the data and
then imports it back to the spreadsheet and to VBA. It then deletes the new
sheet.
MLOpen opens Matlab. Later MLClose closes it. Matlab need not be opened
if it is already open and need not be closed.
MLPutMatrix "AMat", Sheets("Scratch").Range("A1:D5") loads the contents of A1:D5 in sheet Scratch into Matlab variable AMat. Note that the
second argument has no quotes around it. The routines are inconsistent in
this respect.
MLEvalString "SDE2" executes the Matlab statement SDE2. This happens to
be the name of a Matlab m-File in this version and this script file is executed.
MLEvalString "yAMat*y;z=1= executes the two statements yAMat*y=
and z1= in Matlab (the second one is pointless but is included for illustrative
purposes).
MLGetMatrix "AMat", "Scratch!H1:K5" puts the contents of Matlab variable AMat into the spreadsheet range H1:K5. It must have the command
32
CHAPTER 2.
2.7. OBJECTS
2.7
33
Objects
Contents: Objects, Properties, Methods, Classes, Collections, Executing Functions and Subs from VBA.
Object Notation
VBA deals with the objects of EXCEL such as cells, sheets, workbooks, charts,
etc. Given an object, there are usually subobjects included in the object,
properties of the object that can be accessed and changed and methods for
the object that perform calculations on the object or create something. There
are also objects which are collections of other objects of the same type. An
object has a type - when using a variable to store an object, it is declared in a
Dim statement (compulsory under Option Explicit) e.g. Dim Rng As Range.
The hierarchy of objects in an application is a tree, but there are too many
nodes to view diagrammatically.
To view the tree, select Object Browser from the View menu in the VBE. In
the top combobox, select EXCEL from the drop down list. In the column at
the left there appears a list of all the built in classes available in EXCEL.
Click on Application. Application is the root of the Excel tree. On the
right there appears the properties, methods, events and possibly certain
constants that are part of the class. The icon on the right indicates which
it is.
Some of these properties return objects which are themselves classes with
a similar name to the property. For example, Workbook and Workbooks are
also classes, the latter being the Collection of all the instances of the class
Workbook that have been created to date.
Click on Workbooks in the Classes window of the Object Browser. You can
find out the values of the properties listed in the right hand window or the
output of a method which returns a number by entering one of the following
two types of statement in the Immediate Window (which can be inserted
from the View menu):
Debug.Print Application.Workbooks(1).Sheets(1).Range("A1").Width
MsgBox Application.Workbooks.Count
Debug.Print Application.Workbooks.Count
The first pops up a messagebox with the property value, and the second
prints the value in the Immediate Window. At this stage, the value is 1.
34
CHAPTER 2.
2.7. OBJECTS
35
and other methods may have different arguments in different classes. One
must check which arguments are non-optional for each class and use at least
those.
To use a method, use a statement, for example in the Immediate Window,
of the form
Application.Workbooks.Add
If you wish to assign the new Workbook to a variable, then you can use
Dim wkbk As Workbook
Set wkbk = Application.Workbooks.Add
Note: The word Set must appear in an assignment statement involving an
object. This has the effect of adding a new workbook, which will appear
as a new project in the Project Window. There is an optional argument
which allows you to add an existing project which has been saved previously.
If Myproject.xls already exists in the current directory (press the Open
button to find out the current directory), the following will add it as a
project to your running version of EXCEL:
Application.Workbooks.Add "MyProject"
Try the following in the Immediate Window:
Application.Workbooks(1).Sheets(1).Chartobjects.Add 100,100,100,100
This creates a Chartobject in the first worksheet in the Sheets collection of
the first workbook (or project) in the current instance of your application
(look at your Worksheets to find a blank square in one of them.) Note
that the collection of Worksheet objects is Sheets. Find out what the 4
arguments 100,100,100,100 signify by clicking the Chartobjects class and
then its Add method (look at the bar below the Classes Window.) Try
leaving them out - you get an error message, since they are compulsory.
Try this with other properties and methods and explore the tree of your
instance of an EXCEL application. Some of the properties may yield error
messages (they may be required to have been set previously.)
Every created object has a parent in the tree, uniquely defined For example,
in the collection Chartobjects the Parent of an instance of Chartobject
will be the particular worksheet to which it belongs. A Chart has parent
a Chartobject if it is an embedded chart, or the sheet itself if the chart is
located in its own sheet. When a Chartobject is created in some sheet, a
Chart is automatically created as its child.
Objects have Properties and Methods. Properties can be changed and methods executed to give a result. Count is a method of all collections. In the
Immediate Window type
36
CHAPTER 2.
MsgBox Activesheet.Chartobjects.Count
A box will appear, with the number of objects in this collection.
Executing Functions and Subroutines from VBA
There are two possible ways of writing the arguments of functions and subroutines when executing them. HOWEVER in some situations only one of
these is permissible.
Subroutines: We illustrate with the MsgBox subroutine which displays a
(modal) messagebox with a message. To find out all the possible arguments
of this sub, type MsgBox on a new line in the Immediate window and press the
spacebar. A list of arguments appears. Alternatively, put the cursor in the
middle of the word and press F1. VBA help appears for this sub, listing the
arguments (in the Syntax portion of the window.) Arguments with square
brackets are optional. So there is only one required argument for MsgBox,
namely prompt. We will also use title.
Msgbox Activesheet.Name
recognises that Activesheet.Name is the required prompt argument, it evaluates the expression and puts the result in a box with an OK button (the
default). The box is modal in that it must be closed before you can continue.
Msgbox Activesheet.Name, title:= "trial1"
puts a caption in the coloured bar at the top of the box. Or
Msgbox prompt:= Activesheet.Name, title:= "trial1"
uses the argument name prompt in the function call. Optional arguments like
title must use the argument name in the call.
Note: Putting brackets around the arguments instead of writng them without brackets as above will sometimes work but should NOT be done as
it can lead to unpredictable results. On the other hand if we use Call
MsgBox(Activesheet.Name) the brackets are ESSENTIAL. Call should be
AVOIDED if possible, as it is obsolete, and adds confusion. Also Call
MsgBox(prompt:="hello") will work.
To directly assign a (possibly function) value to another variable at initialization, one can use the following (BRACKETS COMPULSORY):
Dim Var1 = Fun(arg1, arg2)
Dim Var2 = 3
When assigning to a variable whose type is some object type, one must use
Set. For example:
Set rng = Range ("A1")
2.8. CHARTS
37
2.8
Charts
38
CHAPTER 2.
This adds a chart to the global Charts collection, and then makes it an
embedded chart in a sheet.
Once created the characteristics can be altered by VBA. See the example that
follows this discussion.
Use Macro Recording to get an example and select the features you need.
(But try to use one of the methods if the macro is different.)
Use Help, and F1 (when the cursor is on a term) to get assistance and to
find further examples. Also use the Drop down menus that appear when you
insert a period after an identifier.
The following example illustrates the procedure. You may have to click on
the area that the graph should occupy to display it.
Sub MyChart()
Before use, place numberical data in D2:E10
Dim chtobj As ChartObject, cht As Chart
datarng As Range, obj As Object
Application.Screenupdating = False
Set datarng = Range("D2:E10")
On Error Resume Next
Sheet1.ChartObjects.Delete
Set chtobj = Sheets("Sheet1").ChartObjects.Add(1, 1, 1, 1)
Set cht = chtobj.Chart
With chtobj
.Top = Range("A1").top
.Left = Range("A1").Left
.Height = 150
.Width = 450
.RoundedCorners = True
End With
With cht
.Type = xlXYScatter
.SetSourceData Source:=Range("D2:E10"), PlotBy:=Columns
.ChartArea.Interior.ColorIndex = 30
.HasLegend = True
With .PlotArea.Fill
2.8. CHARTS
39
.ForeColor.SchemeColor = 50
.BackColor.SchemeColor = 43
.TwoColorGradient Style:=msoGradientHorizontal, Variant:=1
End With
End With
Application.Screenupdating = True
End Sub
A number of things need still need to be done to make the output more
acceptable. The series may be plotted with markers. To eliminate them, use:
cht.SeriesCollection(i).Markers = xlNone
where i is an index to loop through (or use For Each obj In Series.Collection
..... Next).
Also, the fonts may need to be resized, to avoid a default size that is too
large. This applies to the title, axis title and legend. These can be changed
by setting the following to values:
cht.ChartTitle.Font.Size
cht.Axes(xlCategory).Ticklabels.Font.Size
cht.Axes(xlValue).Ticklabels.Font.Size
cht.Legend.Font.Size
40
CHAPTER 2.
2.9
41
End Function
Example 2 Optimisation of Functions with many Arguments
If a function has many arguments the arguments are best combined into an
array which is entered in a spreadsheet range. Suppose for example that the
arguments are entered into cells B1:B40 and that these are the cells that must
be varied to obtain the optimum. A fragment of a suitable function is the
following:
Function g(vec As Variant)) As Double
Dim i As Integer, M As Integer, params() as Double
M=Application.Count(vec)
Redim params(M)
For i = 1 To M
params(i)=vec(i)
Next i
.....
End Function
We would then use
Range("C1").Formula = "=g(B1:B40)"
The appropriate argument of SolverOK would be
SolverOK SetCell:= "C1", MaxminVal:=3, ValueOf:= "0", _
ByChange:= "B1:B40"
Note: If vec were a string variable this would not work. Example 3 To
solve the simultaneous equations y + t = 3, 3y + t = 5.
Sub LinEq()
Dim a As Double, b As Double
Range("G1").Name = "y"
Range("I1").Name = "t"
Range("G2").Formula = "=y+t-3"
Range("I2").Formula = "=3*y+t-5"
Range("I3").Formula = "=G2 ^ 2 + I2 ^ 2"
42
CHAPTER 2.
is maximize
is minimize
is match a specific value (set by argument ValueOf)
cells referenced by CellRef must be integers
cells referenced by CellRef must be 0 or 1
43
44
CHAPTER 2.
2.10
Errors
Note that these are CELL WORKSHEET FUNCTION errors, not runtime
errors in VBA.
Runtime Errors in VBA In VBA, an error (at RUNTIME) that occurs is
described by an intrinsic object Err (that need not be created). Refer to the
HELP in VBA (F1 in the VBE). Look at the entries for Err Object and Err
Object Example. Properties are:
Err.Number
(default property) the number of the error
Err.DescriptionA string description of the error
Err.Clear
Clears the error - can now proceed
and some other possibilities.
Two useful error numbers are
9 Subscript out of range
11 Division by zero
Trapping Errors
When errors occur, control can be transferred to another section which has
code to deal with them, and then control can be transferred back if necessary.
Such error trapping can be done by a variant of the following code:
(program statements)
Exit Sub
Label 1:
2.10. ERRORS
45
The statement
On Error GoTo 0
turns normal VBA error handling on again (after the last error stopped
things). It DOES NOT instruct return to line 0 - heaven knows what it
does exactly.
Note: The most common runtime errors are division by zero (9) and subscript
out of range (11) in numerical work, and a variety of system errors associated
with files when using them in VBA (File referred to does not exist etc.)
Example The following example first uses the On Error GoTo statement to
specify the location of an error-handling routine within a procedure. In the
example, an attempt to delete an open file generates error number 55. The
error is handled in the error-handling routine, and control is then returned
to the statement that caused the error. The On Error GoTo 0 statement
resumes error trapping After return from the handling routine. A different
procedure is used for the next error. The On Error Resume Next statement
is used to defer error trapping to the following line so that the context for
the error generated by the next statement can be known for certain. Note
that Err.Clear is used to clear the Err objects properties after the error is
handled.
Sub OnErrorStatementDemo()
Dim Msg As String, ObjectRef As Object, num As Integer
On Error GoTo ErrorHandler
Enable error-handling routine.
Open "TESTFILE" For Output As #1
Open file for output.
Kill "TESTFILE"
Attempt to delete open file.
On Error GoTo 0
Resumes normal error trapping.
On Error Resume Next
Defer error trapping.
46
CHAPTER 2.
2.10. ERRORS
47
48
CHAPTER 2.
2.11
Userforms
2.11. USERFORMS
49
50
CHAPTER 2.
2. frmFormname.Load
.Show
.Hide
.Unload
For any object in the Userform, "Me" refers to the parent, namely the
Userform e.g.
Unload Me
3. Userforms can contain the following objects. It is best to name them as
indicated below:
Frame
Textbox
CommandButton
OptionbButton
CheckBox
Listbox
Label
SpinBox
frmFrameName
txtBoxName
btnButtonName
optButtonName
chkBoxName
lstBoxName
lblLabelName
spnBoxName
To give these a name, click on the object and change the Name field in the
Properties Window. There are several other controls objects - see the Controls Toolbox.
4. The Control Source property links a cell in a worksheet to the Value property of the object e.g. one can set the ControlSource property to Sheet1!A1.
5. The Caption property can be used to give the object a descriptive title (which
is written somewhere on the object).
6. HINT: When changing a property in the property window, first click on the
text to be changed in the box on the right of the property name to highlight
property value, then double click. This highlights the text, and you can type
in the new text without erasing the old text. ALTERNATIVELY double
click the property name on the left.
7. Multiple Controls
If you have several different possibilities for the user, you can add a Multipage
Control, with tabs to change pages. You can insert material on each page
as if it were a single form.
2.11. USERFORMS
51
Enlarge your form and add a Multipage control. It will by default have
2 tabs. To add more pages, right click on a tab. You will have 4 options:
New page, Delete Page, Rename, Move.
Some properties on the property list of a Multipage: (to get this list,
click on the Multipage border or use the dropdown list in the Properties
Window (in Design mode)).
Value
Style
Tab Orientation
Multirow
Click on a Page to set its properties. Try adding other controls and getting them to work (e.g. SpinButton, ControlBox, TextBox, ListBox,
CheckBox, OptionButton.)
52
CHAPTER 2.
2.12
Creating and Opening a File To work with the data in a file (read or write)
the file must be created if it does not exist, or opened if it does exist. For Help
with the following, enter Open Statement in the VBE Help Index. The following statement creates or opens a file with name pathname - it only creates the
file if mode is Output. (For example, pathname = "c:\direc\myfile.txt".)
filenumber is a unique integer.
Open (pathname) For (mode) As #(filenumber)
brackets
Omit the
Possible values:
Mode:
Input
Output
Append
Filenumber:
There are other arguments and other possibilities for mode (see HELP in
VBE). The above options for mode allows sequential access - other forms of
access are possible.
Working with Directories (You can find further details by consulting the
Help in VBE (NOT IN EXCEL) and entering the command name in the
INDEX). The most important function is
Dir(PathName)
where pathname is a string which may contain wildcards * (any number of
letters) and ? (1 letter) in your pathname, for example, "c:\windows\*.e??"
There is also the possibility of using a second argument
Dir(pathname, attribute)
Dir returns files without regard to attributes. Possible attributes:
vbReadOnly, vbHidden, vbSystem, vbDirectory.
Dir("c:\windows\*.e??") returns the first filename in the current directory matching the pathname.
To get the next matching file use Dir without any arguments.
If no files are left to return, Dir returns the empty string "".
53
dir is a method of the FileSystem object. See the Object Browser and
the next item for information on other methods.
Other useful methods of FileSystem:
ChDir, ChDrive, FileCopy, FileDateTime, FileLen, GetAttr, Kill (Deletes
file), MkDir, Name (renames the file), RunDir, SetAttr
It is best to use an error trapping procedure when working with files, as
there are frequent user and system errors.
Enter the following in a module and run it with a breakpoint at the final
ttbKill. Check the directory and the file in it, reading the contents. Run
to the end and check again.
Sub sb()
On Error Resume Next
Disregards error in following sta
MkDir "c:\temp1\"
Creates new directory
On Error Resume Next
Kill "c:\temp1\aaatr.txt"
Open "c:\temp1\aaatr.txt" For Output As #1
Write #1, "all";
Writes string "all", leaving line ac
Write #1, " done"
Writes "done" on same line,starts ne
Close #1
Closes file #1
Debug.Print Dir("c:\windows\*.e??")
Finds first .exe file
Debug.Print Dir
Finds next .exe file
Debug.Print Dir("c:\temp1\a*")
On Error Resume Next
Kill "c:\temp1\aaatr.txt"
Deletes a file
On Error Resume Next
RmDir "c:\temp1\"
Deletes a directory
End Sub
The following is a program fragment:
Directory = "c:\*.do?"
File = Dir(Directory)
Cells(1,1) = File
Cells(1,2) = FileLen(Directory & File)
Cells(1,3) = FileDateTime(Directory & File)
File = Dir
Next file in "c:\*.do?" matching pathname
Working with Text Files The best way of handling text from files is to
read either individual characters or entire lines (Sequential Access).
54
CHAPTER 2.
Opening To work with the data in a file (read or write) the file must be
opened. As before, use:
Open (pathname) For (mode) As #(filenumber)
CSV Files (Comma Separated Variable). These have data organised in
columns separated by a comma , and in rows or records terminated by
carriage return/linefeed i.e. chr(13) & chr(10). We will only use such
files here. The Open statement with mode Input or Output creates CSV
files.
Reading Files
Input #(filenumber), Data
inputs the text up to next comma into variable Data
LineInput #(filenumber), Data
inputs a line of data (up to chr(13)) into variable Data
Input inputs text as a string without the inverted commas created previously by writing using Write # . . . (see below). LineInput includes all
punctuation.
Input #1,(variable list) Reads into the successive variables listed
e.g.
Input #1, var1, var2
Example:
Sub sb2()
Dim Data As String, r As
Data = "dat"
r = 0
Open "c:\myfile.txt" For
Write #1, Data;
Write #1, Data;
Close #1
Open "c:\myfile.txt" For
Do Until EOF(1)
Input #1, Data
ActiveCell.Offset(r,
r = r + 1
Loop
Close #1
Kill "c:\myfile.txt"
End Sub
Writing to Files
Integer
Output As #1
Input As #1
or LineInput #1 ... to input a line
0) = Data
55
56
CHAPTER 2.
57
Some comments
Use Open in mode Output to write to a file. Then close it and use Open in
mode Input to read from the file. Use Open in mode Append to write to the
end of the file.
Do NOT open .xls, .doc etc files with Open. Use it for text files (.txt perhaps).
If you read a character number, e.g. "12" from a file and write to the
spreadsheet, it will be usable as a number. EXCEL converts strings to numerical types. Also Integer variables are usable as Strings in VBA, for
example:
Dim i as Integer, str As String
i=3
str = "A" & i
Range(str) = "4"
places the number 4 in cell A3.
58
CHAPTER 2.
2.13
59
Dim datastream
Set datastream = filesystem.GetFile(filename).OpenTextStream(1,-2)
datastream has properties such as the position we are at in the file, column
number, row number, AtEndOf(line), AtEndOf(File).
The arguments (1, -2) have other possibilities:
First Argument : 1 for read only, 2 for write only, 3 for appending (to the
end)
Second Argument: -2 is the system default for code type (usually ASCII), -1
Unicode, 0 ASCII
4. To check whether a file exists: there is a Boolean property
FileExist(filename)
5. Reading:
Dim Str As String
Str = datastream.ReadLine
must now parse Str to get data - alternatively
Str = datastream.Read(n)
n an integer - reads n characters
6. Writing:
datastream.Writeline
datastream.Write 5.47
7. When one has finished with the current type of operation, one must close
the file:
datastream.Close
8. Further information: In VBE go to Help|Contents|Visual Basic Language
Reference|Objects and look at FileSystemObject, File Object, Files Collection
- also look at the links on these pages. The read and write methods will be
in Contents|Visual Basic Language Reference|Methods.
9. To store and retrieve numerical data from files:
It is simplest to store one number per line - one does not then have to parse
the input string. (The file will be only slightly larger than one having multiple
data values per line.)
10. The following is an example of the use of Method 2 of file processing for input
and output of matrices.
60
CHAPTER 2.
Sub
Dim
Dim
Dim
61
For i = 1 To numrows
For j = 1 To numcols
matrix(i, j) = datastream.Readline()
Next j
Next i
datastream.Close
Exit Sub
ErrorHandler:
MsgBox Err.Description, vbOKOnly, "Unhandled Error"
datastream.Close
End Sub
Sub ReadSaveMatrix_Excel_to_File(wsht As Worksheet, strRngName As String, _
strFile As String)
For example, wsht could be Sheets("Sheet1")
Dim i As Integer, j As Integer
Dim numrows As Integer, numcols As Integer
Dim matrix() As Double
numrows = wsht.Range(strRngName).Rows.Count
numcols = wsht.Range(strRngName).Columns.Count
ReDim matrix(1 To numrows, 1 To numcols)
For i = 1 To numrows
For j = 1 To numcols
matrix(i, j) = wsht.Range(strRngName).Cells(i, j).Value
Next j
Next i
SaveMatrixToFile filename:=strFile, matrix:=matrix
End Sub
Sub SaveToFile()
Dim fName As String, mat(1 To 3, 1 To 3) As Double, i As Integer, j As Integer
For i = 1 To 3
For j = 1 To 3
mat(i, j) = i * j
62
CHAPTER 2.
Next
Next
SaveMatrixToFile "fnoo.txt", mat()
End Sub
Sub ReadFromFile()
Dim mat() As Double
ReadMatrixFromFile "fnoo.txt", mat()
End Sub
Sub RangeMatrixToFile()
ReadSaveMatrix_Excel_to_File Sheets("Sheet2"), "A1:C3", "fnoo.txt"
End Sub
2.14. EVENTS
2.14
63
Events
We will briefly introduce events and their use. Associated with each object
is a set of events. VBA allows one to transfer control from executing something in EXCEL to a program which will do something that you want to
do, and after completion return control to EXCEL. For example, there are
events of the type Click CommandButton1 (occurs when this button has been
clicked), the Calculate event (occurs before recalculation takes place), the
BeforeRightClick event, the BeforeDoubleClick event, the SelectionChange
and Change events, opening and closing of a workbook events and many more.
For example, to use events associated with a WorkSheet that is active, say
Sheet1, switch to the VBE and click on Sheet1 in the Project Window, then
look at the two combo boxes near the top on the right. Click on the left hand
box and choose WorkSheet. Then click on the right hand box. All the events
associted with WorkSheet are displayed. If you click on one, a sub skeleton
appears in the text portion of the window with the name of your event. You
can then fill in the actions you want taken when the event occurs in VBA.
All the embedded objects in the sheet will appear in the left hand box, and their
events in the right hand box. If you want to know the events associated with
a non-embedded object, find the object in the Object Browser - the events are
listed among the properties and methods.
An example of the use of an event is to display or hide a chart. Suppose you
have a chart in the worksheet. You can place a piece of text in one of the cells,
like Hide/Show, and use the SelectionChange event. In the code, check if the
new selection, given by Selection.Cells(1,1).Value, is equal to Hide/Show
and if it is, you can use
ActiveSheet.ChartObjects(i).Visible = False
(or set it to True) to perform the hiding or showing.
64
CHAPTER 2.
2.15
Class Modules
65
mr As Double
msigma As Double
mT As Double
mq As Double
In our case all the variables are Double variables, so we do not indicate this
as a prefix. Other types are given a prefix.
Some of the basic properties could be made available to the user, so that they
can be checked or altered. Such a property requires two functions if it is to be
a read/write property, a Property Get routine and a Property Let routine,
and only one of these if it is to be read-only or write-only. They are of a
special type, and one of these properties in our case is
Public Property Get X() As Double
X = mX
End Property
Public Property Let X(ByVal NewX As Double)
mX = NewX
End Property
Note that the property is given a new name, X in our case. It is convenient
to give the property the same name as the variable to which it corresponds,
namely mX, but without the prefix m. The user will access the property by one
of the two types of statement:
VariableName = BS.X
BS.X = 100
The first calls Property Get, and the second calls Property Let with NewX
as 100. A similar pair of routines must be set up for each property - see the
program below.
We also use subs and functions in the class module which are Methods in object oriented terminology. There are four Methods, d1, d2, Cll, Pt. These
calculate the values of the parameters d1 and d2, and the values of the Call
and the Put respectively, in terms of the values of the basic properties. They
are accessed by the user by such statements as
VariableName = BS.Cll
66
CHAPTER 2.
Although none of these methods have arguments, they could have had. They
would then be used as follows:
VariableName = BS.function1(arg1,arg2)
BS.sub1 arg1:= val1, arg2:= val2
In order to create various BS models, we need a way of creating instances of
this class, and then we need a way of defining the properties of the specific
instance through the user. To do the latter, we could:
(i) Write a sub or function which sets the properties.
(ii) Write a sub or function which reads values we have entered in a spreadsheet and uses these to set the properties.
(iii) Design an input form.
(iv) Use the InputBox facility, which in our case might look like
mX = val(InputBox("Enter the Strike Price"))
To create a new instance of the class, it is often desirable to place it in a
variable which is private to the set of routines in the module being used,
but available to all the routines in the module. One would then put in the
Declarations Section of the module:
Private mBS As BS
and in the sub that needs to create the instance:
Set mBS = New BS
Alternatively, if one is using only one sub, we could use the following in the
sub:
Dim mBS as New BS
67
Sub bsc()
Dim mBS As New BS
mBS.x = Sheet1.Range("A1")
mBS.So = Sheet1.Range("A2")
mBS.rate = Sheet1.Range("A3")
mBS.sigma = Sheet1.Range("A4")
mBS.t = Sheet1.Range("A5")
mBS.q = Sheet1.Range("A6")
Sheet1.Range("C1").Value
Sheet1.Range("C2").Value
Sheet1.Range("C3").Value
Sheet1.Range("C4").Value
= mBS.Cll
=mBS.Pt
= mBS.d1
=mBS.d2
End Sub
Later on we will set up a new class called mBSs which organizes a collection
of instances of the BS class. We could also discuss the possibility of creating
new events for the class, and creating error handling routines. However the
basics discussed thus far will suffice for most of our purposes.
A Class definition must be entered in a Class Module which can be inserted in
a project through the Insert menu. Classes can be exported to .cls files and
imported to any project. Both Import and Export is accomplished through
the appropriate menu item in the File menu.
The name of the Class si the same as the name displayed under Class Modules
in the Project window (initially, it is Class1 or similar). To change the name,
press F4 to bring up the Properties menu and alter the name field.
There follows now a listing of the BS Class.
68
CHAPTER 2.
69
70
CHAPTER 2.
Collections
Given a class, it is possible to construct a collection class which will keep
track of instances of the original class as they are created. In EXCEL, for
example, the WorkSheet class has a collection class Sheets, which houses all
the sheets in a Workbook that have been created. In general, if the classname
is Xyz then the collection of instances of such classes is named Xyzs.
The collection is created by dimensioning a variable As Collection and
setting it to a new instance of the class that has been created. We illustrate
this procedure by creating the collection BSs of Black-Scholes objects - see
below.
The holding variable mBSs is declared Private (which must be done in the
Declarations section.) A collection is a class which has built in methods
Add, Remove and built in Read-Only properties Item, Count. The methods add and delete an instance, the property Item finds the instance with
a given name or index and the property Count returns the number of instances in the collection. However, since the variable mBSs is Private, these
methods and properties are not available to the user. The variable could
be declared Public, but this would not allow the collection to control their
use. For example, it may be necessary to define the values of properties of
the original class, and the user cannot be trusted to do it correctly on his
own. So it is necessary to write Public versions of these properties and
methods, which use the private versions.
the public Add method here creates the BS class instance, fills in all its
properties and calls the private Add method to add the instance to the
collection. The instance can be created optionally with a name given by
the input string variable sKey. This can be used to refer to the instance
(see comments in the function definition below.) If the optional argument
is not included, the instance can be referred to by a positive integral Index.
The Remove and Count property routines are self explanatory.
There are two events, Class Initialize and Class Terminate which occur on initialization and termination of the collection. The first is used to
set the variable mBSs to an new instance of a collection. The second is used
to remove the content of this variable.
The routine NewEnum is difficult to explain properly, and may be omitted.
If it is omitted, then there is only one way to run through all instances in
the collection, namely
Dim i As Integer
For i=1 To (variable).Count
(Statements involving Item(i))
Next
71
72
CHAPTER 2.
73
Count = mBSs.Count
End Property
mBSs.Remove vntIndexKey
End Sub
Testing Routine
Sub BStest()
This is a routine testing various aspects of the BS class, BSs Collection
Dim objBS As BS, v As BS, i As Integer
Dim objBSs As BSs
74
CHAPTER 2.
"Call", objBS.Cll
"Put", objBS.Pt
"X", objBS.X
"rate", objBS.rate
"Count", objBSs.Count
2.16
75
76
CHAPTER 2.
Double
(double-precision
floating-point)
Currency
(scaled integer)
Decimal
Date
Object
String
(variable-length)
String
(fixed-length)
Variant
(with numbers)
Variant
(with characters)
User-defined
(using Type)
Storage
size
1 byte
2 bytes
2 bytes
4 bytes
8 bytes
8 bytes
14 bytes
8 bytes
4 bytes
10 bytes
Length
of string
16 bytes
22 bytes
Number
required by
elements
Range
0 to 255
True or False
-32,768 to 32,767
-2,147,483,648 to 2,147,483,647 Single (singleprecision floating-point) 4 bytes -3.402823E38 to
-1.401298E-45 for negative values; 1.401298E-45
to 3.402823E38 for positive values
-1.79769313486231E308 to -4.94065645841247E324 for negative values; 4.94065645841247E-324
to 1.79769313486232E308 for positive values
-922,337,203,685,477.5808
to
922,337,203,685,477.5807
+/-79,228,162,514,264,337,593,543,950,335
with
no
decimal
point;
+/7.9228162514264337593543950335
with
28 places to the right of the decimal;
smallest non-zero number is +/0.0000000000000000000000000001
January 1, 100 to December 31, 9999
Any Object reference
+ string length 0 to approximately 2 billion
1 to approximately 65,400
Any numeric value up to the range of a Double
+ string length Same range as for variablelength String
The range of each element is the same as the
range of its data type.
Note: Arrays of any data type require 20 bytes of memory plus 4 bytes for
each array dimension plus the number of bytes occupied by the data itself.
77
78
CHAPTER 2.
Keywords
Chr
Format, LCase, Ucase
DateSerial, DateValue
Hex, Oct
Format, Str
CBool, CByte, CCur, CDate,
CDbl, CDec, CInt, CLng, CSng,
CStr, CVar, CVErr, Fix, Int
Day, Month, Weekday,Year
Hour, Minute,
Asc
Val
TimeSerial, TimeValue
Keywords
CBool, CByte, CCur, CDate, CDbl, CDec,
CInt, CLng, CSng, CStr, CVar, CVErr, Fix, Int
Set
Boolean, Byte, Currency, Date, Double, Integer,
Long, Object, Single, String, Variant (default)
IsArray, IsDate, IsEmpty, IsError, IsMissing, IsNull, IsNumeric, IsObject
Trigonometric functions.
General calculations.
Generate random numbers.
Get absolute value.
Get the sign of an expression.
Perform numeric conversions.
Rounnding.
Keywords
, , , /, Mod e.g. 10 Mod 3:
1,
+, & (string op.), =
Atn, Cos, Sin, Tan
Exp, Log, Sqr
Randomize, Rnd
Abs
Sgn
Fix, Int
Round(x[,No. Decimal Places])
result
79
Keywords
StrComp
StrConv
Format, Lcase, Ucase
Space, String
Len
Format
LSet, Rset
InStr, Left, LTrim, Mid, Right, RTrim,
Trim
Option Compare
Asc, Chr
Prefix Conventions
Data
Prefix
Type
Boolean
bln
Currency
cur
Double
dbl
Date/Time dtm
Integer
int
Long
lng
Single
sng
String
str
Variant
vnt
Logical Operators
And
Or
Not
80
CHAPTER 2.
Keywords
Date, Now, Time
DateAdd, DateDiff, DatePart
DateSerial, DateValue
TimeSerial, TimeValue
Date, Time
Timer
Keywords
ChDir
ChDrive
MkDir
RmDir
CurDir
FileDateTime
GetAttr
FileLen
Dir
SetAttr
2.17. EXERCISES
2.17
81
Exercises
1. Write a subroutine which takes as input a range in the form A1:C50 and
clears the range of all content, all borders and also of colour. Allow the user
instead to clear these from the currently selected range. [If necessary, get
ideas from running a macro].
2. Write a subroutine for estimating the cumulative normal distribution by
means of a polynomial. Look up an appropriate algorithm in Press etal
or Hull or somewhere similar.
3. Write a subroutine which multiplies two variables representing matrices. Input also the matrix sizes. Do similarly for a subroutine for taking the transpose of a matrix.
4. Write three functions which return values drawn from a Uniform, Poisson
and Binomial distribution.
5. Write a function for solving an single equation of the form f (x) = 0 by
Newtons method and by the Newton-Bailey method. [Look them up if necessary].
6. Extend the previous question to the case of more than one equation.