You are on page 1of 39

Excel VBA: No Experience Necessary - Lesson 1

We all know that Microsoft Excel is an extremely powerful piece of software, with more capabilities than most of us
(including myself) could ever hope to wrap our tiny brains around. However, you may sometimes find yourself spending
what seems like too much time doing repetitive or manual tasks in Excel. Shirley, you thought, there must be a better
way. Well, unless you know someone named Shirley, you may have to learn how to do something about it yourself.
Excel, Word, and PowerPoint each include a version of the programming language Visual Basic called VBA (Visual
Basic for Applications), which can be used to automate such tasks. In this series of articles WEwill attempt to give you
just enough knowledge to make you dangerous, even if you have little or no background in programming.
The approach Im going to take is to go through a few examples without getting into a lot of technical discussion and
definitions yet. My goal is just to get you started. In the spirit of Its OK to not know as long as you know what you dont
know Ill point out a few topics that WEwill not be discussing yet. Ill try to circle back in a future article to cover such
things, or at least point you to another resource.

Recording a Macro
A macro is a stored sequence of actions which may be executed as a single action (and which may be executed
multiple times). A macro is also known as a subroutine. (Ill use the terms interchangeably here.) Your VBA code will be
in the form of subroutines and functions.
Excel, like Word, allows you to record a series of actions as a macro. When you record a macro, Excel actually
produces VBA code to mimic your actions. Try this:

Open Excel

Click on menu item Tools, Macro, Record New Macro

In the Record Macro box, type in the macro name, Example1. Click OK

You should now see a small toolbar labeled Stop with two buttons.

Click on cell B2

Type Hello Excel and push your Enter key

Highlight cell B2 again and change the font to bold by clicking the B button on the toolbar.

Stop recording your macro by clicking the first button, with a small blue square, on the toolbar which appeared
when you started recording.

Youve now written four lines of VBA code! To see it, go back to the menu and click on Tools, Macro, Visual Basic

Editor. (Keyboard shortcut Alt + F11).


In the Visual Basic editor, you will see a tree structure on the left representing your Excel workbook and its associated
code. The folder called Microsoft Excel Objects includes an item for each worksheet in your workbook, as well as an
item for the workbook itself. There is a second folder called Modules in which you should find an item called Module1.
Double-click on Module1 to display the code you recorded. It should look something like this:
Example 1.
Sub Example1()
'' Macro1 Macro
' Macro recorded 12/19/2003 by Mark Shirley Thorpe
Range("B2").Select
ActiveCell.FormulaR1C1 = "Hello Excel"
Range("B2").Select
Selection.Font.Bold = True
End Sub

Running a Macro
Next try running your macro. First clear cell B2, then click on Tools, Macro, Macros. Click on Macro1 and click the
Run button, or just double-click on the macro name.

Visual Basic Editor


As WEmentioned earlier, the Visual Basic Editor is accessible by selecting menu item Tools, Macro, Visual Basic
Editor, or by using Alt + F11 on your keyboard. (Alt + F11 will also switch you back to Excel itself from the Editor.) The
Project Window, which appears on the left side of the screen holds a tree structure which shows up to three folders
for each Excel file currently open:
1. Microsoft Excel Objects: one object representing the workbook, one for each sheet in the workbook
2. Forms: user-defined forms contained in the spreadsheet (covered later)
3. Modules: collections of procedures and functions
Double-click on a module or worksheet to see the code associated with it. The code window will appear on the right.
Important Note!
You can usually figure out how to code any action in Excel by recording it in a macro and viewing the resulting macro
code.

Visual Basic Editor

Loopy
This next example will introduce you to the for loop which is particulary useful in Excel. A for loop allows you to repeat
the same action a specific number of times. Type in, or copy/paste the following lines into your VBA Editor, below your
Macro1:
Example 2.
Sub Example2()
For x = 1 To 5
Cells(x, 3).Select
Selection.Vaue = x + 1
Next x
End Sub
Next run the macro directly from the VB Editor by putting your cursor somewhere within the macro and clicking on the
small blue triangle button in the toolbar. (Or push F5 on your keyboard.) Switch back to Excel with Alt + F11. You will
see the numbers 2 through 6 in column C.
Weve used the variable x to represent the row number of a series of cells and weve used a For Next statement to

loop through the first five rows.

Stepping Through Code


Clear column C, then resize the VB Editor window and the Excel window so that you can see both at the same time.
Click to put the cursor within the Example2 macro code, and push F8. This will step you into the code. Push F8
repeatedly to see your code executed a line at a time.

Referencing a Cell
In the two examples above, weve used two different methods for referencing a cell. In the first example, we used
Range, while in the second example we used Cells. There are a variety of ways to use these two, but Ill cover just the
basics. Range can be used to access one or more cells by specifying the cells in the standard Excel notation, where
the column is represented by a letter, and the row by a number. Cells is used to access a single cell by specifying row
number and column number, in that order. Try adding these lines to a macro and stepping through them with F8:
Example 3.
Sub Example3()
Range("D5").Interior.ColorIndex = 3
Range("C2:E4").Value = 100
Cells(7, 2).Borders.LineStyle = xlDouble
End Sub
Generally, if youre using a loop as we did in example 2, youll use Cells rather than Range. WEmentioned above that
you can learn how to do almost any Excel action in VBA by recording a macro and looking at the resulting code.
However, if you want to do the same action repeatedly, your best bet is to take the recorded code, put it inside a for
loop, and replace the Range cell reference, (e.g. Range(B2) from Example 1), with Cells, where you can use a
variable to specify the row and/or column.

An Actual Useful Example


Example 3 is a subroutine which will sort the active worksheet by first column, then remove any duplicates. You should
notice a number of things:

The first line sorts the contents of the spreadsheet using Cells.Sort. The column to sort by is specified with the
Key1 argument. Arguments is a topic WEhavent covered yet.

Ive used ActiveSheet.UsedRange.Rows.Count to determine how many total rows are actually used in the
worksheet. This is an example of Excel objects, properties, and collections, topics WEhavent covered yet.
Even if you dont know much about these things, ActiveSheet.UsedRange.Rows.Count can be extremely

valuable to you in writing Excel VBA code.

Im counting backwards in my For loop by using Step 1. You can use Step with other values, for example
Step 2 if you want to highlight every other row. Im counting backwards in this case because WEam deleting
rows. If WEcount forwards, WEwill be skipping over rows which have moved up to take the place of rows which
have been deleted.

If you havent already figured this out from the previous examples, you can get (or change) the contents of a
cell by using .Value

WEam using an If Then statement to determine if the contents of two different cells are equal. If youve done
any programming at all, you already know about If Then. It allows you to check whether a certain condition
is true, and, if so, execute one or more subsequent statements.

Example 4.
Sub RemoveDuplicates()
Cells.Sort Key1:=Range("A1")
totalrows = ActiveSheet.UsedRange.Rows.Count
For Row = totalrows To 2 Step -1
If Cells(Row, 1).Value = Cells(Row - 1, 1).Value Then
Rows(Row).Delete
End If
Next Row
End Sub
This subroutine is included in the spreadsheet linked below. The spreadsheet contains data which will allow you to see
the subroutine in action. While this subroutine can be useful, youll notice that the data in this spreadsheet is definitely
not. The data is copied on Sheet2, so if you want to run RemoveDuplicates more than once, simply copy the original
data from Sheet2 back to Sheet1 before rerunning.

Something to Try
If we havent bored you to tears, or hopelessly confused you, and youre still interested in learning to do more with
Excel VBA, heres an exercise for you to try on your own
Starting with the spreadsheet above, modify the RemoveDuplicate function above so that it keeps track of the total
number of instances of a given record (e.g. number of Shaggys), and puts the total for each record in column 3. When
finished, these numbers should sum to 100, the total number of rows in the original data.

Excel VBA: No Experience Necessary - Lesson 2

In Lesson 1, we started with an introduction to the basics of writing VBA code in Excel, with a couple of simple
examples.
Well start this lesson with the solution to the last homework. We started with a subroutine called
RemoveDuplicates, which sorted the active worksheet by column 1, then deleted any row (aka record) which was a
duplicate of a previous row (in terms of its column 1 value). The challenge was to modify RemoveDuplicates so that it
would keep track of the total number of instances of a given record, and put the total for each record in column 3.
Well, obviously well need a counter. For creativitys sake, well call it Count. We will start it out at 1, to represent the
record which will not be deleted, then add 1 to it each time we delete another duplicate. See the new lines (bolded) in
Example 1 below.

Example 1
Sub RemoveDuplicates()
Cells.Sort Key1:=Range("A1")
totalrows = ActiveSheet.UsedRange.Rows.Count
Count = 1
For Row = totalrows To 2 Step -1
If Cells(Row, 1).Value = Cells(Row - 1, 1).Value Then
Rows(Row).Delete
Count = Count + 1
End If
Next Row
End Sub
If youre not already familiar to writing code, the line Count = Count + 1 will look odd to you, but dont think of it as an
algebraic equation. This is just how we add one to the current value of Count.
So now were counting! However, we have two more things to do: put the count for a particular record in the
spreadsheet, and reset the counter when we get to a new record. For this we will add an else clause to our if-then
statement. The if statement in our subroutine is checking to see if the value in a particular row, column 1 is the same as
the value in column 1 of the previous row (Row 1). If this is true, we have a duplicate, so we delete it, and add one to

our counter. If they are different, however, this means that we are changing from one record to a different record, which
in turn means we should record our counter value for the old record, and start the counter over again for our new
record. See the new lines in Example 2

Example 2
Sub RemoveDuplicates()
Cells.Sort Key1:=Range("A1")
totalrows = ActiveSheet.UsedRange.Rows.Count
Count = 1
For Row = totalrows To 2 Step -1
If Cells(Row, 1).Value = Cells(Row - 1, 1).Value Then
Rows(Row).Delete
Count = Count + 1
Else
Cells(Row, 3).Value = Count 'save count for old record
Count = 1 ' reset counter for new record
End If
Next Row
' Don't forget last record (which is actually first)...
Cells(1, 3).Value = Count
End Sub
A couple of notes:

We had to add a line at the end to store the counter value for the topmost record. Since this is the last record
we come across in our code, and the first in the spreadsheet, there is no previous record to compare it to, so
we never get to it within our else clause.

You can (and should) put comments in your code, as Ive done above (in green). In VB, anything after a single
quotation is a comment.

Variables and Data Types


In the example above, Ive used variables like Row, totalrows, and Count to store values.
A variable is a named element which can be used in your code to store a value that can change during execution of the
code. Variables are generally of a specific type (numeric, text, etc) and are declared using the Dim statement.

For example:
Dim iCounter as integer
Dim sName as string
WEdid not declare variables in any of the examples so far, and VBA does not force you to declare your variables.
However, WEhighly recommend you not only declare your variables, but tell VBA to force you to declare them. You do
this by putting a line at the top of your code (above all of your subroutines) which says Option Explicit. VBA will give
you a variable not defined error message whenever it encounters an undeclared variable. Without this, you could
mistype one of your variable names and not know it. VBA would just assume it was a new variable and initialize it to
zero or . If youre working with a large piece of code, this could be a big debugging headache.

Example 3
Option Explicit
Sub Hello()
Dim iCol as integer
Dim lRow as long
Dim sText as string
iCol = 2
lRow = 3
sText = Hello Excel
Cells(lRow, iCol).Value = sText
End Sub

Excel Objects, Properties, and Methods


In addition to the standard data types described above, Excel provides a number of defined object types representing
various elements specific to Excel. Examples of Excel Objects include Application, Workbook, Worksheet, and Range.
Application represents the entire Excel application. Workbook represents an Excel .xls file. Worksheet represents a
single sheet (tab) within a workbook.(A Range represents a set of one or more cells. These types of objects are used to
control the behavior of Excel from your VBA code. An object is like a variable in that it can store a value, but is more
complex in that it can hold multiple values (properties) and has its own set of defined actions (methods) it can perform.
In the Excel VBA help file, the help page for any Excel object type has hyperlinks at the top for the lists of properties
and methods which apply.
Some examples of Excel objects and their properties and methods:

Application Object
Properties: Workbooks, ActiveWorkbook, ActiveSheet, Caption, Charts, DisplayAlerts, CutCopyMode
Methods: CheckSpelling, Run, Quit
Workbook Object
Properties: Worksheets, ActiveSheet, ActiveChart, Name, Path, FullName, FileFormat
Methods: Activate, Save, SaveAs, Close, Protect
Worksheet Object
Properties: Name, Index, Cells, Columns, Rows, Type, Visible
Methods: Activate, Select, Calculate, Copy, Delete, Move, PrintOut, Protect, Unprotect
Range Object
Properties: Count, Columns, Rows, Cells, Value
Methods: Activate, Select, Find, Copy
There are many more Excel objects than the four Ive listed, but these are probably the most widely-used. Also, each of
the four objects Ive listed has many more properties and methods.
To refer to an objects property or method, simply write the object name followed by a dot/period followed by the
property or method name.
For example, in the line
Application.ActiveSheet.Cells(2,3).Value = 6
ActiveSheet is a property of the Application object and is an object of type Worksheet. Cells is, in turn, a property of the
Worksheet object which represents a Range object. Value is a property of the Range object.
What can make this confusing is the fact that property names and object type names in Excel are often the same. The
Workbook object and Worksheet object each have a property called Application, which represents the Application
object. Range is also both a property and an object type.

Implied Objects
Property names can sometimes be used without object qualifiers. In other words, in some cases you can specify the
property name, without specifying the object you are referring to.
For example, the line we used above

Application.ActiveSheet.Cells(2,3).Value = 6
Can also be written as
ActiveSheet.Cells(2,3).Value = 6
Although ActiveSheet is a property of Application, you may use ActiveSheet without specifiying Application, since
there is only one Application object.
The same line above may also be written as
Cells(2,3).Value = 6
In this case, Cells is a property of a Worksheet object, but you can use it without specifying which worksheet you are
referring to. In this case, Excel will use whichever sheet is active (currently displayed in Excel) as a default.

Collections
Many types of objects in Excel come in groups. There may be multiple workbooks open in Excel at a given time. Each
workbook may have multiple worksheets. A worksheet can have multiple graphs. These multiple objects are gathered
together in whats called a collection. The collection itself is an object, with its own set of properties and methods.
For example, the Application object has a property called Workbooks, which represents a Workbook Collection object.
It includes a single Workbook object for each workbook currently open in Excel. Similarly, the Workbook object has a
property called Worksheets which is a Worksheet Collection object, including one Worksheet object for each worksheet
in the workbook.

Referencing Items in A Collection


The simplest way to reference an item in a collection is by number. All objects in a collection have a numeric index,
starting with 1. To reference an element in a collection by number, simply put the number in parentheses after the
collection object. Try the following example
Open Excel and create a new workbook. Open the VB Editor (Alt + F11). Double-click on ThisWorkbook to bring up a
code window on the right. Paste in the following lines:

Example 4
Option Explicit
Sub SeeSheetNames()

Dim iSheetCount As Integer


Dim iSheet As Integer
iSheetCount = ActiveWorkbook.Worksheets.Count
For iSheet = 1 To iSheetCount
Worksheets(iSheet).Activate
MsgBox Worksheets(iSheet).Name
Next iSheet
End Sub
Switch back to Excel and run the subroutine by using Alt + F8 to bring up the macro list and double-clicking on
SeeSheetNames. As you see, the subroutine activates each sheet in the workbook and displays the name of that sheet
in a message box.
A couple of notes on Example 4:

WEcould have used just Worksheets.Count instead of ActiveWorkbook.Worksheets.Count. When the


workbook object is not specified, Excel VBA uses the current active workbook by default.

WEmentioned above that each type of collection object has its own set of properties and methods. The one
property which is common to all collections is Count, which gives you the number of items currently in that
collection.

MsgBox is a VB function you may use to display text in a popup box.

Another way to reference workbooks or worksheets is by name. Instead of using a number in the parentheses, put the
name (in double quotes) in the parentheses. This is helpful when you are working with multiple workbooks, or a
spreadsheet with a lot of worksheets with specific purposes.
Examples:
Workbooks(ClassSample1.xls).Activate
Worksheets(TestValues).Cells(1,1) = 60
You can also refer to the Workbook in which the code you are running is contained with the keyword ThisWorkbook.
This is useful when you are using one workbook and its code to modify the data in another workbook.
For example:
ActiveWorkbook.Worksheets(1).Name = ThisWorkbook.Worksheets(1).Name
This line changes the name of the first worksheet in whichever workbook is currently active to be the same as the

name of the first worksheet in the workbook which includes this code.

Another Exercise
More homework for you to try if you like... Create a workbook with a CreateWorkbook subroutine which automatically
creates a new workbook, then sets the names of each worksheet in the new workbook according to the names it reads
from the first column of its own first worksheet. In other words, you start with a workbook whose first worksheet looks
like Figure 1. Running the CreateWorkbook subroutine will automatically create a new workbook which looks like
Figure 2.

Figure 1 Figure 2.
You may need some hints:

You will need to use the Add method of the Workbooks collection to create the new workbook.

You will need to determine how many names are in the worksheet, i.e. how many worksheets will need to be
created in the new workbook. See the use of UsedRange in example 1 above.

You will need to add or delete worksheets in the new workbook to get the correct number. You will use the Add
method of the Worksheets collection and the Delete method of the Worksheet object.

You will be well-served to use a while loop when adding or deleting worksheets. If you are not familiar with a
while loop, it looks something like this:

Dim x As Integer
While x < 5
x = x + 1
Wend
Everything between the While and the Wend repeats until the While condition is true.

You will be dealing with two workbooks. Use ThisWorkbook and ActiveWorkbook to distinguish between them.

You may use the assumption that the new workbook, when you create it, becomes the active workbook.

Excel VBA: No Experience Necessary - Lesson 3

A quick recap
In Lesson 1, we covered the introductory topics of: recording and running a macro, the Visual Basic Editor, the for
loop, and referencing a cell. In Lesson 2, we covered variables and data types, Excel objects, properties, and
methods, and object collections. In this, Lesson 3, we will touch on debugging, user-defined functions, and using Excel
functions in VBA code.
But first, the solution to the exercise at the end of Lesson 2. The challenge was to write a subroutine called
"CreateWorkbook" which would automatically create a new workbook and set the names of each worksheet in the new
workbook according to names stored in the first sheet of the initial workbook.
The first step is easy. A new Excel workbook can be created by simply using the Add method of the Workbooks
collection:
Example 1a.
Sub CreateWorkbook()
Workbooks.Add
End Sub
Next we need to determine how many worksheets should be in the new workbook. We can do this by counting how
many names are listed in the original workbook (the workbook with the VBA code). Keep in mind that we now have two
workbooks open, the original and the new one created by our subroutine. When we added the new workbook, it
became the "active" workbook, but since we want to count the names which are stored in the original workbook, we
need to reference it as "ThisWorkbook". This signifies that the code is referencing the workbook in which it (the code) is
contained.
We are assuming that the names are contained on the first worksheet, so we will use ThisWorkbook.Worksheets(1).
You may remember from Lesson 1 that we can find out how many rows are actually used in a worksheet by looking at
the "UsedRange" property of the Worksheet object.

Example 1b.
Sub CreateWorkbook()
Dim iSheetCount As Integer
Workbooks.Add
iSheetCount = ThisWorkbook.Worksheets(1).UsedRange.Rows.Count
End Sub
The next step is to set the correct number of worksheets in the new workbook. To do this we will use two separate
"while" loops. One will be used if we need to remove worksheets, the second if we need to add worksheets. As
WEmentioned above, when a new workbook is added, it becomes the active workbook, so we can reference the new
workbook using "ActiveWorkbook".
Example 1c.
Sub CreateWorkbook()
Dim iSheetCount As Integer
Workbooks.Add
iSheetCount = ThisWorkbook.Worksheets(1).UsedRange.Rows.Count
Application.DisplayAlerts = False
' If we have too many worksheets, delete one at a time until
' we reach the correct number:
While ActiveWorkbook.Worksheets.Count > iSheetCount
ActiveWorkbook.Worksheets(1).Delete
Wend
' If we dont have enough worksheets, add more one at a time
' until we reach the correct number:
While ActiveWorkbook.Worksheets.Count < iSheetCount
ActiveWorkbook.Worksheets.Add
Wend
End Sub

The line "Application.DisplayAlerts = False" is handy when you want your VBA code to do something that Excel
normally gives you an "Are you sure?" message about when you try to do it by hand. Without this line of code, Excel
will display a warning message each time the code tries to delete a worksheet. Setting the DisplayAlerts property of the
Application object to False turns off such messages.
Lastly, we need to set the names of the worksheets in the new workbook according to the contents of the original
workbook. For this we will use a simple "for" loop, reading each name from ThisWorkbook, and assigning it to the
Name property of each Worksheet object in the ActiveWorkbook.
Example 1d.
Sub CreateWorkbook()
Dim iSheetCount As Integer
Dim iSheet As Integer
Workbooks.Add
iSheetCount = ThisWorkbook.Worksheets(1).UsedRange.Rows.Count
Application.DisplayAlerts = False
' If we have too many worksheets, delete one at a time until
' we reach the correct number:
While ActiveWorkbook.Worksheets.Count > iSheetCount
ActiveWorkbook.Worksheets(1).Delete
Wend
' If we dont have enough worksheets, add more one at a time
' until we reach the correct number:
While ActiveWorkbook.Worksheets.Count < iSheetCount
ActiveWorkbook.Worksheets.Add
Wend
For iSheet = 1 To iSheetCount
ActiveWorkbook.Worksheets(iSheet).Name = _
ThisWorkbook.Worksheets(1).Cells(iSheet, 1).Value
Next iSheet
End Sub
Note that we use the iSheet variable as both a reference into the Worksheets collection of the new workbook, and as

the row number when reading the names from the original workbook.
You may also notice that an underscore character can be used to split a long line of code over two lines. The
underscore must be preceded by a space.
Debugging
When something goes horribly awry in your code, or your code doesnt produce the results you expect, you can use
the Debug and Run menus in the Visual Basic Editor to help locate the source of the problems. Below are some of the
most useful commands:
Command

Shortcut Key Toolbar

Description

Button
Run

F5

Executes the current subroutine or function

Toggle

F9

Sets or Clears a breakpoint, which pauses

Breakpoint
Step Into

execution of the code


F8

Steps through each line of code (when one


subroutine is called from another this will "step into"
the called subroutine)

Step Over

Shift + F8

Steps through each line of code (when one


subroutine is called from another this will "step
over" the called subroutine)

Reset

Stops execution of your code. You can restart


execution only from the beginning.

Break

Ctrl+Break

Temporarily halts execution of your code. You can


continue execution from the where it left off.

Quick Watch

Shift + F9

When execution is paused, displays the value of the


highlighted variable. (You may also view the value
of a variable by pausing the cursor over it)

Before you run your code, save your workbook. It doesnt happen often, but you may inadvertently have written code
which is truly evil and will cause Excel to crash. You dont want to lose your code, diabolical though it may be. Also, pay
particular attention to the keyboard shortcut Ctrl+Break. If your code has gone into an infinite loop, or something is
taking much longer than you expected, Ctrl+Break is the easiest way to stop it. Once execution has been halted, you
can either Reset it, or step through from where it was paused, using F8.
Try using the debugging commands to step through the homework example solution. As you step through line by line,
you can actually Alt+Tab (or Alt+F11) between the VBA Editor and Excel to see each worksheet added and each
worksheet name as it changes.

Functions
All of the examples that weve used so far have been in the form of subroutines, aka macros. In Lesson 1,
WEmentioned that your VBA code would be in the form of subroutines and functions, but WEhave yet to define what a
function is, or what the difference is between a function or a subroutine.
Well, the main difference is that a function returns a value. In other words, you can call a function from a subroutine (or
another function), and use the value that the function passes back. This may be more easily understood with a simple
example.
Example 2.
Function UpperFileName() As String
UpperFileName = UCase(ActiveWorkbook.Name)
End Function
Sub ShowFileName()
MsgBox UpperFileName()
End Sub
Here weve defined a simple function called UpperFileName. Weve declared the function type (string) in a way similar
to how we declare a variable, using "As" followed by a data type. This represents which data type will be returned by
the function. In this example, the function returns a string, which it creates by getting the file name of the current active
workbook, and converting it to upper case (using the VB function UCase). We return this string value by using the
function name as if it were a variable, and setting it equal to the string. The subroutine ShowFileName calls the function
UpperFileName and displays the returned value in a message box.
(This may be apparent to you if youve written code before, but if youre one of the brave souls whos never
programmed before and made it this far, you should note that you can call one subroutine or function from another
subroutine or function.)
Function and Subroutine Parameters
To really make a worthwhile function, you will need the ability to send values into the function. These values are known
as either parameters or arguments. For example, suppose you wanted to write a function which converted a
temperature from degrees fahrenheit to degrees celsius. This function would need to take as input a temperature in
fahrenheit. You can do this by listing the parameter with its type within the parentheses that follow the function name.
Example 3.
Function Celsius(dFahrenheit As Double) As Double
Celsius = (dFahrenheit - 32) * (5 / 9)

End Function
Sub ConvertTemperature()
Dim dtemperatureF As Double
Dim dtemperatureC As Double
dtemperatureF = Cells(1, 4).Value
dtemperatureC = Celsius(dtemperatureF)
Cells(2, 4).Value = dtemperatureC
End Sub
The function, named Celsius, is declared as a double, meaning that it returns a double-precision floating point value. It
takes, as a parameter, a double value called dFahrenheit. It convert dFahrenheit to the corresponding celsius
temperature, then returns this value.
The subroutine ConvertTemperature reads a fahrenheit value from cell D1, converts it to celsius using our function, and
places the result in cell D2.
Functions can take more than one parameter. Each parameter should be separated by a comma. The function below,
for example, can convert a number to either celsius or fahrenheit, depending on the value of the second parameter,
bConvertToCelsius. This is a Boolean variable, which means that it can have a value or either True or False.
Example 4.
Function CelsiusOrFahrenheit(dTemperature As Double, _
bConvertToCelsius As Boolean) As Double
If bConvertToCelsius Then

'dTemperature is in Fahrenheit,
'so convert to Celsius

CelsiusOrFahrenheit = (dTemperature - 32) * (5 / 9)


Else

'dTemperature is in Celsius, convert to Fahrenheit


CelsiusOrFahrenheit = dTemperature * (9 / 5) + 32

End If
End Function
Subroutines can also take parameters. Note, however, that a subroutine which requires parameters cannot be called
directly from Excels Tools, Macros menu. It must be called from another subroutine (or function).
Using Your Functions in the Spreadsheet
The coolest thing about writing your own functions is that you can actually use them directly in your spreadsheet. All of
the examples above are contained in the Excel VBA Article 2 Example Solution.xls (link above). If you havent already
been adding the examples to your own workbook, download the Article 2 Example Solution workbook.

In order to use your function in the spreadsheet, you only need to make one minor change. In the VBA Editor, add the
word "Public" before the word "Function". This simply makes the function accessible from outside the VBA module in
which it resides.
Next go to the spreadsheet, enter a number (temperature) in one cell, then click in an empty cell. Select Insert,
Function from the main menu. The last item in the Function Category list on the left is called User Defined. Click on this
and you will see your user-defined functions listed magically on the right. Double-click on Celsius. You will then be
presented with a box in which you are prompted for the parameter which the function requires, dFahrenheit. Click on
the cell in which you typed a temperature, then click OK. Your temperature has been converted from Fahrenheit to
Celsius!

WEdont know about you, but WEwas pretty excited when WElearned WEcould write my own functions, then use them
in my spreadsheet. Then again, maybe youre not as big a geek as I.
Using Excel Functions in Your Code
Just as you can use your own functions in a spreadsheet, you can also use Excel functions in your code. This is done
using the WorksheetFunction object (which is actually a property of the Application object). The WorksheetFunction
object provides your VBA code with access to Excel worksheet functions. The example below (also in the Example
Solution spreadsheet) calculates the average and standard deviation for each column of numbers on the second
worksheet, and places the results below the numbers.
Example 5.
Sub UseExcelFunctions()
Dim iColumnCount As Integer
Dim lRowCount As Long
Dim iCol As Integer
Dim dAverage As Double
Dim dStdDev As Double
Worksheets(2).Activate
' Count number of columns and rows in use...

iColumnCount = ActiveSheet.UsedRange.Columns.Count
lRowCount = ActiveSheet.UsedRange.Rows.Count
' Cycle through each non-empty column...
For iCol = 1 To iColumnCount
' Use the Average and StDev Excel functions to
' calculate values for each column...
dAverage = WorksheetFunction.Average(Columns(iCol))
dStdDev = WorksheetFunction.StDev(Columns(iCol))
' Place results below existing data...
Cells(lRowCount + 2, iCol).Value = dAverage
Cells(lRowCount + 3, iCol).Value = dStdDev
Next iCol
End Sub
"Why Mark?" you ask. "Why write code to do this when WEcan simply put the actual formulas right in the
spreadsheet?" While WEadmit WEdo not often use Excel functions in my VBA code, WEcan think of a couple of
instances in which this might come in handy. One example might be if you had to calculate a number of statistics for
multiple sets of data, each on a separate worksheet within your workbook, and list all of these statistics on a summary
worksheet. This might be easier to do with code. Also, there may be times when you need to send a spreadsheet of
calculated data to a client, and dont want to have any formulas in the spreadsheet, only data. This is a circumstance
WEoften encounter in my work.
An Exercise for You
If youre game, heres an exercise for you to try. WEwill present the solution in my next article. Your assignment, should
you choose to accept it, is to write a function called "DayOfYear" which takes one parameter, a Date, and returns an
integer which represents which day of the year that date represents. For example, if the date is Feb 1, 2004, the
function should return 32. If Dec 31, 2004, it should return 366. Date is another VBA data type and represents both
date and time. You will use various VBA date-related functions, such as Month, Day, and Year to write your function.
Take a look at the VBA Excel help file for more information on the Date data type and these function.
The second part of the exercise is to write a second function called "ZodiacSign", which also takes a Date parameter,
and returns a string representing the sign of the zodiac which corresponds to that date (Capricorn, Aquarius, etc). You
will call your DayOfYear function from the ZodiacSign function. Add some dates in your spreadsheet and apply each of
your functions to each date.
Here is some sample data you should try to match:

Date

DayOfYear

ZodiacSign

1/20/1999

20

Aquarius

12/31/2003

365

Capricorn

12/31/2004

366

Capricorn

6/16/2001

167

Geminwe

7/10/1986

191

Cancer

3/19/1990

78

Pisces

9/6/1982

249

Virgo

One last hint Ive covered the "if" statement briefly, and the "else" clause that can go with it. For your functions, you
will set up a series of conditions using "elseif", which allows your code to check if a second (or third, fourth) condition
is true when the previous condition is not. See example 6 below.
Example 6.
If iScore >= 90 Then
sGrade = "A"
ElseIf iScore >= 80 Then
sGrade = "B"
ElseIf iScore >= 70 Then
sGrade = "C"
ElseIf iScore >= 60 Then
sGrade = "D"
Else
sGrade = "F"
End If
Good luck.

Excel VBA: No Experience Necessary - Lesson 4

In Lesson 3 we learned about writing our own Excel functions, as well as how to incorporate Excel built-in functions in
our VBA code. This month, we will cover the exciting topic of creating your own forms! But first, of course, we will start
with
Solution to Last Months Exercise
Last lesson we closed with an exercise for you to try which involved writing two functions: DayOfYear, which
represents which day of the year, in integer form, a date represents, and ZodiacSign, which returns the zodiac sign for
a particular date.
Lets start with the function declaration for DayOfYear. The function will need to take a Date as a parameter, and return
an integer:
Public Function DayOfYear(SomeDate As Date) As Integer
To calculate the day of the year, well first determine the month and day of SomeDate using the VBA date functions
Month() and Day(). In this case, Day represents the day of the month, not the day of the year.
Example 1a.
Public Function DayOfYear(SomeDate As Date) As Integer
Dim iMonth As Integer
Dim iDay As Integer
iMonth = Month(SomeDate)
iDay = Day(SomeDate)
Well start at zero, and add the appropriate number of days for each month which precedes our date. Then we add the

number of days into the current month (i.e. the day of the month)...
Example 1b.
Public Function DayOfYear(SomeDate As Date) As Integer
Dim iMonth As Integer
Dim iDay As Integer
iMonth = Month(SomeDate)
iDay = Day(SomeDate)
DayOfYear = 0
If iMonth > 1 Then
DayOfYear = DayOfYear + 31
End If
If iMonth > 2 Then
DayOfYear = DayOfYear + 28
End If
If iMonth > 3 Then
DayOfYear = DayOfYear + 31
End If
...
If iMonth > 11 Then
DayOfYear = DayOfYear + 30
End If
' Add number of days into the current month:
DayOfYear = DayOfYear + iDay
End Function
For the sake of brevity, we left out months 4 through 10, but you get the picture. The last thing we need to do is account
for the possibility that our date occurs in a leap year. To do this we will use the Year() function, and the Mod operator,
which calculates the remainder of one number divided by another. We wont insult your intelligence by explaining that a
leap year is a multiple of four, so when divided by four, the remainder is zero. We will put this if statement inside our if
iMonth > 2 clause.

Example 1c.
If iMonth > 2 Then
DayOfYear = DayOfYear + 28
' Add one extra day if this is a leap year:
If Year(SomeDate) Mod 4 = 0 Then
DayOfYear = DayOfYear + 1
End If
End If
We gave a hint last month that you would be using a series of elseif statements, and it certainly can be done that way,
but upon further review we decided that using separate if statements, one for each month, would be the "cleaner", if
longer, way to implement this function. If youre interested in seeing an alternative implementation which uses elseif,
see function DayOfYear_Alt1 in the solution download (see above). An even shorter way which involves calling another
user-defined function, DaysInMonth, is presented in function DayOfYear_Alt2.
For the function ZodiacSign, we will use elseif statements, simply figuring out, based on the day of the year, which sign
represents that day. We also have to adjust back one day for leap years
Example 1d.
Public Function ZodiacSign(BirthDate As Date) As String
Dim iDayofYear As Integer
iDayofYear = DayOfYear(BirthDate)
' Adjust back one day if a leap year, and later than Feb 28...
If Year(BirthDate) Mod 4 = 0 And iDayofYear > 59 Then
iDayofYear = iDayofYear - 1
End If
If iDayofYear < 20 Then
ZodiacSign = "Capricorn"
ElseIf iDayofYear < 50 Then
ZodiacSign = "Aquarius"
ElseIf iDayofYear < 81 Then
ZodiacSign = "Pisces"
ElseIf iDayofYear < 111 Then

ZodiacSign = "Aries"
ElseIf iDayofYear < 142 Then
ZodiacSign = "Taurus"
ElseIf iDayofYear < 173 Then
ZodiacSign = "Gemini"
ElseIf iDayofYear < 205 Then
ZodiacSign = "Cancer"
ElseIf iDayofYear < 236 Then
ZodiacSign = "Leo"
ElseIf iDayofYear < 267 Then
ZodiacSign = "Virgo"
ElseIf iDayofYear < 297 Then
ZodiacSign = "Libra"
ElseIf iDayofYear < 327 Then
ZodiacSign = "Scorpio"
ElseIf iDayofYear < 357 Then
ZodiacSign = "Sagittarius"
Else
ZodiacSign = "Capricorn"
End If
End Function
Creating Your Own Forms
If you want to spruce up your humble Excel spreadsheet with a handsome user interface, creating your own
UserForms is the only way to go.
To create a form, bring up the Visual Basic Editor from Excel. Select Insert, UserForm from the main menu. You will be
presented with a blank form with a caption of UserForm1. Your form, and each of the controls you will place on it, has
a set of properties which determine how it will look and behave. To view these properties, click on menu item View,
Properties Window (or type F4). The left column lists each property, and the right column lists the value of each
property, which you may change. The first property listed is (Name). You will use the Name property in the code which
will bring up your form. Try changing the Caption property, and toying with some of the other properties. You can also
resize your form using the border, and small boxes, which appear around its outside edge. (Note that the tree structure
on the left, in the Project Explorer window, now has a folder called Forms and that your UserForm1 appears beneath
it.)
Next, lets drop a few controls on our form. You will do this using the controls Toolbox. Click on menu item View,
Toolbox. (If it is grayed out, try clicking on your user form first. Toolbox is disabled when focus is in the Properties

window.)

Click on the capital A button to create a Label control. A label is simply text that appears on your form. Click and drag a
box on your form. The Properties window now shows you the properties of your first control, named Label1. In the
Caption property, type Enter Some Data Here or something slightly cleverer.
Below your label, add a TextBox control by clicking on the lowercase ab button in the toolbox. Change the (Name)
property of the TextBox to txtData. Next add two CommandButton controls (small 3-D rectangle button on the right
side of the Toolbox). For the first button, change the Name property to cmdAdd and the Caption property to Add. For
the second, change the name to cmdClose and the caption to Close.
You should now have a form which looks something like this

Invoking Your Form


Just as each of the Excel objects (see Lesson 2) has both properties and methods, so does your UserForm, and each
of its controls. You can think of them as additional types of Excel object. Weve already seen the properties of each in
the Properties window in the Visual Basic Editor. Generally, you wont use many UserForm or control methods, but
UserForm has a method without which you would not be able to Show your form. Its called Show.
To bring up our sample form, well try something else new adding a control directly to our spreadsheet. Back in Excel
itself, click on View, Toolbars, Control Toolbox. This Toolbox is quite similar to the Toolbox in the VB Editor. Click on the
button for the CommandButton control (3-D rectangle), then place it on your spreadsheet by clicking and dragging. Like
the buttons you drew on your form, this button also has properties. To view them, click the button in the upper right of

the Toolbox, the hand holding a card (or is that an electic bill?). Change the name to cmdShowForm, and the caption
to Show My Form. Next, double-click on the button. This will switch you back to the VB Editor and automatically
create an empty subroutine called cmdShowForm_Click within your Sheet1 worksheet object. As you may guess, this
is the subroutine which will be called when the user clicks the button. Within this subroutine, enter a single line of code:
Example 2.
Private Sub cmdShowForm_Click()
UserForm1.Show
End Sub
Next, switch back to Excel and click on the Design Mode button, in the upper-left corner of the Control Toolbox. This is
the button which appears to be someone stabbing a shark with a very stubby pencil. Not a good idea. Next click on
your Show My Form button and voila! Theres your user form. Youll notice that while you can type information into
the textbox, neither of your buttons actually does anything when you click on them. Thats next. For now, close your
form by clicking the X button in the upper right.
Writing Code for a User Form
In the Visual Basic Editor, bring up UserForm1. Double-click on the Close button. Just as when we double-clicked on
the Show My Form button in the spreadsheet, double-clicking the Close button automatically creates a subroutine
called cmdClose_Click, which will be called when the user clicks the Close button. The VBA command to close a form
is Unload. Therefore we could close our form with the line of code Unload UserForm1. However, since this code is
UserForm1s own code, we can instead type Unload Me. Me is a VBA keyword that a form can use to refer to itself.
Example 3.
Private Sub cmdClose_Click()
Unload Me
End Sub
That was the easy one. Next, lets switch back to the form. We mentioned above that the form appears under a Forms
folder in the Project Explorer window on the left. To view the form, you can double-click on its name in the Project
Explorer, or highlight it and click menu item View, Object (keyboard shortcut Shift+F7). To view the code for a form,
highlight it and click menu item View, Code (keyboard shortcut F7.
Double-click the Add button to create the cmdAdd_Click subroutine. The first thing we will do with this button is, when
the user clicks it, read the contents of the TextBox and display it in a message box. The contents of a VBA TextBox
control is accessible by using the Text property. We will declare a string variable called sData, set it equal to the Text
property of the TextBox, then display it in a message box:

Example 4.
Private Sub cmdAdd_Click()
Dim sData As String
sData = txtData.Text
MsgBox sData
End Sub
Give it a try. Switch back to Excel, click Show My Form, enter some text, then click Add. Try your Close button too.
Next lets add the data to the spreadsheet instead of showing it in a message box. We already know how to set the
value of a worksheet cell. The only question is where to put it. For this example, we will add each piece of data to the
end of a list in column A. Well declare a variable called lRowNum, determine how many rows are already used (with
ActiveSheet.UsedRange.Rows.Count), then set lRowNum to the next row. One quirk of Excel will throw a small
monkey wrench into this plan. Even if the spreadsheet is completely empty, ActiveSheet.UsedRange.Rows.Count will
be set to 1. To get around this, we will first check to see if cell A1 is empty. If so, we will put the data there. If not, count
the used rows:
Example 4.
Private Sub cmdAdd_Click()
Dim sData As String
Dim lRowNum As Long
sData = txtData.Text
' Put the data in the current worksheet:
If Cells(1, 1).Value = "" Then
lRowNum = 1
Else
lRowNum = ActiveSheet.UsedRange.Rows.Count + 1
End If
Cells(lRowNum, 1).Value = sData
End Sub
Try it again. Youll notice two small problems. After we add the text to the spreadsheet, it remains in the TextBox. Also,
the focus is now on the Add button. This means that to make another entry, we have to first click on (or tab back to) the
TextBox, then we have to erase the previous entry before we can make a new one. These problems are solved easily.
Just as we can use the Text property of the TextBox to read its contents, we can use it to set the contents. Also, each

control you place on your form has a method called SetFocus. Add two lines of code to your subroutine and try it again:
Private Sub cmdAdd_Click()
Dim sData As String
Dim lRowNum As Long
sData = txtData.Text
' Put the data in the current worksheet:
If Cells(1, 1).Value = "" Then
lRowNum = 1
Else
lRowNum = ActiveSheet.UsedRange.Rows.Count + 1
End If
Cells(lRowNum, 1).Value = sData
' Clear text box and set focus for next entry:
txtData.Text = ""
txtData.SetFocus
End Sub
Much better!
Youve had but a taste of user forms in Excel. If youd like an exercise to practice with, try making a phone list form for
yourself. Store names in column A, and phone numbers in column B. This will be similar to the exercise weve just
done, but in addition to adding new phone numbers, your form should allow you to go up and down your list to view
existing numbers, change existing entries, and delete entries. Your form should have one TextBox for name and
another for telephone number. It should have Previous, Next, Add, Delete, and Close buttons. Couple of hints:
You can write code which will be called as soon as your form comes up, by creating a subroutine called:
UserForm_Activate. This is used to set the initial contents of the form. For example, if we wanted the form we created
above to initially display the first string in our list, we would add:
Private Sub UserForm_Activate()
txtData.Text = ActiveSheet.Cells(1, 1).Value
End Sub
You will need to keep track of which row number the form is currently displaying. The easiest way to do this will be to
declare a variable within the code of your form, but not within any of its subroutines. At the top of the code window for
your form, add the line:

Dim lCurrentRow As Long


You can then use this variable in any of your subroutines. You will want to set it to 1 in your UserForm_Activate
subroutine, then change its value accordingly each time the user clicks Previous or Next.
Your Add button will not work quite the same as the one we created in the example above. Instead, your Add button
should set lCurrentRow to the first unused row in your spreadsheet, and clear both TextBox controls. You will then save
whatever the user has entered to the spreadsheet when the user clicks either Previous, Next, or Close.
If you want a bit more of a challenge, try adding a dropdown list box (ComboBox control) to your form, and filling it
with all existing names. When the user selects an item from the list, set the TextBox controls to the selected persons
name and telephone number. You can also try adding more TextBox controls to your form to turn the phone list into an
address book.

Excel VBANo Experience Necessary: Lesson 5

In this lesson we will walk through, step by step, the project described at the end of last months Lesson 4. Theres a
fairly significant number of tasks to accomplish to implement this, so it deserves a thorough dissection.
The project involves creating an Excel phone list with a user form serving as an interface. The form is to include one
TextBox for name and another for telephone number, and Previous, Next, Add, Delete, and Close buttons.
WEencourage you to open up Excel and follow along with each step.

Step 1 Create the Form


Starting with a new workbook (Excel file), bring up the VBA Editor (Alt+F11). Select Insert, User Form from the menu. If
the Properties window does not appear automatically, bring it up with View, Properties Window (or F4). Change the
Name property of the form to PhoneListForm, and the Caption property to My Phone List.

Step 2 Add Controls


Still in the VBA Editor, if the Controls Toolbox is not already open, bring it up with View, Toolbox. Each control types
name appears in a hint balloon as you pass your mouse over its button. Add the following controls to your form, and
change the properties as specified:

Label control set Caption property to "Name:"

TextBox control set Name property to "txtName"

Label control set Caption property to "Telephone:"

TextBox control set Name property to "txtPhone"

CommandButton control set Name to "cmdPrev" and Caption to "Previous"

CommandButton control set Name to "cmdNext" and Caption to "Next"

CommandButton control set Name to "cmdAdd" and Caption to "Add"

CommandButton control set Name to "cmdDelete" and Caption to "Delete"

CommandButton control set Name to "cmdClose" and Caption to "Close"

Resize and move your controls so that your form looks something like this:

Step 3 Implement UserForm_Activate Subroutine


We mentioned a couple of hints at the end of the last article. The first was to create a subroutine called
UserForm_Activate to set the initial contents of the form. To do this, right-click on the form and select View Code. This
will bring up the code window for your form and create a subroutine called UserForm_Click. Were not really going to
do anything special when the user clicks on the form, so go ahead and change the subroutine to UserForm_Activate.
This subroutine is executed when the form is first brought up.
We will set the initial contents of the two TextBox controls using the Text property. The values will come from the first
two cells in the first row.
Private Sub UserForm_Activate()
' Read initial values from Row 1:
txtName.Text = Cells(1, 1).Value
txtPhone.Text = Cells(1, 2).Value
End Sub
In this step, lets also implement the Close button, since its just a single line of code. Switch back to the UserForm
window and double-click on the Close button to add its subroutine, cmdClose_Click. (You can also do this directly from
the code window by selecting cmdClose from the dropdown list of the forms controls which appears at the top-left of

the code window.) Use Unload Me to close the form:


Private Sub cmdClose_Click()
Unload Me ' Close the form
End Sub

Step 4 Add a Button to the Spreadsheet


This is more or less copied straight out of last lesson. Were going to add a button to the spreadsheet itself which will,
when clicked, bring up our form. Switch back to Excel and click on View, Toolbars, Control Toolbox. Click on the button
for the CommandButton control, then place it on your spreadsheet by clicking and dragging. To view the buttons
properties, click the button in the upper right of the Toolbox. Change the name to cmdShowForm, and the caption to
Show Form.
Next, double-click on the button. This will switch you back to the VB Editor and automatically create your
cmdShowForm_Click subroutine. Add the line of code to show your form:
Private Sub cmdShowForm_Click()
PhoneListForm.Show
End Sub
Next, lets try out the form. Switch back to Excel and click the Design Mode button in the Control Toolbox (upper left).
Put a name and telephone number in cells A1 and B1, then click the Show Form button. Your form should now appear,
with the name and number from Row 1 appearing in the text boxes.
Note: Make sure you always close your form when youre ready to switch back to the VBA Editor. You will be unable to
change any code while your form is still active.

Step 5 Add a Row Number Variable


Since we will be allowing the user to move up and down the list, well need a way to keep track of which row number
the form is currently displaying. We will do this by creating a "form level" variable. This is a variable declared within the
code of the form, but not within any of its subroutines. At the top of the code window for your form, add the line:
Dim lCurrentRow As Long
A form level variable can be used in any of the forms subroutines. Since our form starts by displaying the contents of
row number 1, we should initialize this variable to 1 in the UserForm_Activate subroutine. To be really good
programmers, well then use this variable in the next two lines to read the name and telephone number. That way, if we
decide for some reason to start in a row other than the first, well only need to change one line of code:

Private Sub UserForm_Activate()


' Read initial values from Row 1:
lCurrentRow = 1
txtName.Text = Cells(lCurrentRow, 1).Value
txtPhone.Text = Cells(lCurrentRow, 2).Value
End Sub

Step 6 Implement Previous, Next Buttons


In the VBA Editor, bring up the user form and double-click the Next button to create its subroutine cmdNext_Click. In
this subroutine we will move from the current row to the next row by adding 1 to our lCurrentRow variable, and reading
in the name and telephone number from the new row. To add 1 to a VB variable, use the algebra-defying statement:
var = var + 1:
Private Sub cmdNext_Click()
' Increment row number:
lCurrentRow = lCurrentRow + 1
' Show contents of new row in the form:
txtName.Text = Cells(lCurrentRow, 1).Value
txtPhone.Text = Cells(lCurrentRow, 2).Value
End Sub
As you may have guessed, code for the Previous button will be remarkably similar. However, we have to be a bit more
careful. Excel will not be pleased with us if the user is already in row 1, clicks the Previous button, and we try to read
values from row 0. We will need to use an if statement to make sure the row number is greater than 1 before we
attempt to subtract from it:
Private Sub cmdPrev_Click()
' Show previous only if not already in first row:
If lCurrentRow > 1 Then
' Decrement row number:
lCurrentRow = lCurrentRow - 1
' Show contents of new row in the form:
txtName.Text = Cells(lCurrentRow, 1).Value
txtPhone.Text = Cells(lCurrentRow, 2).Value
End If
End Sub

Now switch back to Excel and try out your form. You should be able to move up and down the list. Of course, if you
havent typed names and numbers into the spreadsheet, there wont be much to see.
Which brings usme to the next point. Somethings missing! We are supposed to be able to use our form to add new
names and numbers. Of course, we havent implemented the Add button yet, but suppose we are skipping merrily
through our list with the Next button, and make a change to one of the existing entries. If we click Next again, that
change should be saved back to the spreadsheet before showing the next row, right? (Right.)
Well, that should be easy. In our Previous and Next subroutines, we will simply read the contents of the form and save
it back to the spreadsheet before we change rows. We already have this line of code to read the name from the
spreadsheet and display it in the form:
txtName.Text = Cells(lCurrentRow, 1).Value
To go the other way, i.e. to read the name from the form and save it in the spreadsheet, we simply turn the line of code
around:
Cells(lCurrentRow, 1).Value = txtName.Text
Our revised subroutines, then, are:
Private Sub cmdPrev_Click()
' Show previous only if not already in first row:
If lCurrentRow > 1 Then
' Save form contents before changing rows:
Cells(lCurrentRow, 1).Value = txtName.Text
Cells(lCurrentRow, 2).Value = txtPhone.Text
' Decrement row number:
lCurrentRow = lCurrentRow 1
' Show contents of new row in the form:
txtName.Text = Cells(lCurrentRow, 1).Value
txtPhone.Text = Cells(lCurrentRow, 2).Value
End If
End Sub
Private Sub cmdNext_Click()
' Save form contents before changing rows:
Cells(lCurrentRow, 1).Value = txtName.Text

Cells(lCurrentRow, 2).Value = txtPhone.Text


' Increment row number:
lCurrentRow = lCurrentRow + 1
' Show contents of new row in the form:
txtName.Text = Cells(lCurrentRow, 1).Value
txtPhone.Text = Cells(lCurrentRow, 2).Value
End Sub
Try your form again. Youll see that were in the homestretch.

Step 7 Implement Add Button


Since the Next and Previous buttons now do the actual saving of data back to the spreadsheet, the Add button has a
fairly simple job. Since each row in the spreadsheet represents a different person, to add a new person to the list, we
simply have to find an empty row to put them in. Of course, we can tell how many rows are currently in use with
UsedRange.Rows.Count. So our Add button will simply set lCurrentRow accordingly and clear the text boxes on the
form. After the user types in the new name and number, clicking Previous or Next will save.
Private Sub cmdAdd_Click()
' Set current row to first empty row, i.e. one row after
'

the last row currently in use:

If Cells(1, 1).Value = "" Then


lCurrentRow = 1

' (list is empty - start in row 1)

Else
lCurrentRow = ActiveSheet.UsedRange.Rows.Count + 1
End If
' Clear the form for user to add new name:
txtName.Text = ""
txtPhone.Text = ""
' Set focus to Name textbox:
txtName.SetFocus
End Sub
Try it out. Bring up your form, type in a name and number, click Next or Previous. It works, doesnt it? Well, yes and
no...
If you hadnt noticed, we have a slight problem here. Suppose you are trying to add multiple names to the spreadsheet.
You should be able to click Add, type in a name/number, then click Add again to type in the next name/number, without

having to click Next to save the first name/number. This is basically the same issue we had with our Previous and Next
buttons. By clicking Add, were changing the current row, which means we should first store any changes the user
made to the original row. This will allow us to add multiple new names consecutively, and will also take care of the case
where the user makes a change to one of the names, then clicks Add to add a new name.
To save the contents of the form before going to the first blank row, we add the same code we used in
cmdPrevious_Click and cmdNext_Click:
Private Sub cmdAdd_Click()
' Save form contents before changing rows:
Cells(lCurrentRow, 1).Value = txtName.Text
Cells(lCurrentRow, 2).Value = txtPhone.Text

While were at it, lets add the same code to our Close button, so any changes the user was making before closing the
form are not lost:
Private Sub cmdClose_Click()
' Save form contents before closing:
Cells(lCurrentRow, 1).Value = txtName.Text
Cells(lCurrentRow, 2).Value = txtPhone.Text
Unload Me ' Close the form
End Sub

Step 7 Implement Delete Button


Last button! If the user clicks the delete button, we simply need to delete the current row (name/number) from the
spreadsheet. But since were conscientious programmers, well put in one of those annoying Are you sure? message
boxes first.
The MsgBox function, which we mentioned briefly at the end of Lesson 2 as a simple means to display information,
also allows you to set an optional second parameter controlling what types of buttons are displayed at the bottom of the
message (OK/Cancel, Yes/No, Yes/No/Cancel, etc) as well as what, if any, type of icon youd like to display on the
message box (question mark, i for information, red X, etc). For example, the line of code:
MsgBox "Do you really want to delete it?", vbQuestion + vbYesNo
will show a message box with a question mark icon and Yes and No buttons. vbQuestion and vbYesNo are predefined
VBA constants.

In order to tell whether the user clicked Yes or No, we have to check the return value of the MsgBox function. A
message box with Yes and No buttons will return either vbYes or vbNo (again, VBA constants).
If MsgBox("Do you really want to delete it?", _
vbQuestion + vbYesNo) = vbYes Then
...
End If
In our code, well use the name of the person currently displayed in the form as part of the message box. We will also
specify the caption of the message box, Confirm Delete using an optional third parameter of the MsgBox function.
After deleting the row, we will display the contents of the new current row.
Private Sub cmdDelete_Click()
Dim smessage As String
smessage = "Are you sure you want to delete " + txtName.text + "?"
If MsgBox(smessage, vbQuestion + vbYesNo, _
"Confirm Delete") = vbYes Then
' Delete current row:
Rows(lCurrentRow).Delete
' Show contents of new current row in the form:
txtName.text = Cells(lCurrentRow, 1).Value
txtPhone.text = Cells(lCurrentRow, 2).Value
End If
End Sub

Step 8 Tighten Up That Code


Youve probably noticed by now that there are a couple of basic things our code is doing in several different places. We
have six different subroutines for our form, and five of them include code to set the text in the forms text boxes. Four of
the subroutines save the contents of the form back to the spreadsheet. Since we have only two text boxes, this is not
much of an issue. But just suppose you decided to really make something out of this little project, and began to add
more text boxes for address, city, state, zip, fax, e-mail address, website and pet names. Clearly you dont want to
have to put code for each of these text boxes in nine different places. What you need is to take your redundant code
and break it out into separate subroutines, such as LoadRow and SaveRow:
Private Sub LoadRow()
txtName.text = Cells(lCurrentRow, 1).Value
txtPhone.text = Cells(lCurrentRow, 2).Value
End Sub

Private Sub SaveRow()


Cells(lCurrentRow, 1).Value = txtName.text
Cells(lCurrentRow, 2).Value = txtPhone.text
End Sub
Go back and change your other subroutines to call these new subroutines. For example:
Private Sub cmdPrev_Click()
' Show previous only if not already in first row:
If lCurrentRow > 1 Then
' Save form contents before changing rows:
SaveRow
' Decrement row number:
lCurrentRow = lCurrentRow - 1
' Show contents of row in the form:
LoadRow
End If
End Sub
Now, for each new textbox you add, you will simply need to add one line of code each to the LoadRow and SaveRow
subroutines.

Do More
There are other things we could do to this project as part of the goal to tighten things up. For example:

add code to the SaveRow subroutine which checks each TextBox to make sure it is not empty before adding it
to the spreadsheet. If one is empty, display an error message.

write code in cmdNext_Click which prevents the user from going more than one row past the last entry in the
list.

write code in cmdDelete_Click which ignores the delete button if currently on an empty row

There are even more things you could do to make this project more useful, besides adding additional fields for address,
e-mail, etc:

Add a List button which brings up a separate form listing all of the names in the spreadsheet. Allow the user
to double-click on a name to change the first form to that person.

Allow entries on multiple worksheets by including on your form a dropdown list of the sheet names. For
example, you might have one sheet called personal and a second sheet called work. The dropdown list on
your form would include each of these sheet names. By selecting a different sheet from the dropdown, the form

would switch to show the set of names/numbers from that worksheet.

You might also like