Excel Vba
Excel Vba
Excel Vba
Table of Contents
Page 2
Excel 2010 Visual Basic for Applications
Page 3
Excel 2010 Visual Basic for Applications
The Process
Macros usually start with a recording but recorded macros do not give you enough
flexibility to control the whole process that you want to execute. Often you will need to
introduce decision making and repetition into your macro code. This has to be done by
typing-in control structures and assignment statements in the VBA language.
In this example there is a range of cells on the worksheet and where the cell value is
greater than 500 is has to be formatted in bold and the cell value doubled. Conditional
Formatting is of no use for this as it can not change the cell value. We must use a macro.
End Sub
End Sub
Page 4
Excel 2010 Visual Basic for Applications
Terminology
You are using the Microsoft Visual Basic for Applications (VBA) language to automate the
manipulation of the Microsoft Excel application.
You need to know about how to address or access the various parts or objects of the
Excel application and how these objects are organised in the document object model.
You control the flow of this process using the control structures of VBA.
In the world of Excel, you describe this type of process as a macro; short for
macroinstruction. In the world of Visual Basic you describe it as a procedure, a set of
sequential instructions to complete a single process.
Procedures are stored in Modules. Modules are stored in Workbooks. The collection
comprising of Worksheets, Modules and their containing Workbook file is called a Project.
End Sub
Sub MyOtherSub(x)
End Sub
Page 5
Excel 2010 Visual Basic for Applications
Control Structures
Control structures are required for decision-making and repetition or looping.
Decision making
Decision-making structures are If-Then-Else and Case Statements. If-Then-Else has two
syntax structures, a Case Statement only one.
If-Then-Else
In-Line Form
If conditional_test Then True_ statement Else False_ statement
Only one True or False statement is available. Else is optional. The structure is contained
on one logical line. A logical line can be broken into more than one physical line by using
line-continuation. See Line Continuation on page 27.
Block Form
If conditional_test Then
True_ statement
True_ statement
ElseIf conditional_test Then
True_ statement
ElseIf conditional_test Then
True_ statement
Else
False_ statement
End If
Multiple True or False statements. The ElseIf and Else clauses are optional. The structure
is contained on multiple lines. Use either the Block form or the In-line form; do not try to
combine them or you will cause a Compile error.
Examples
Sub InLineIfForm()
x = 50
End Sub
Sub BlockIfForm()
x = 100
End Sub
Page 6
Excel 2010 Visual Basic for Applications
Case Statements
Comparing a single test expression against multiple possible values. Each case test
consists of a test and an outcome to that test. The outcome statements may be multiple
lines and may also be omitted.
SelectCase TestExpression
Case 5 'TestExpression is equal to 5.
Statements
Statements
Case Is > 25 'TestExpression is greater than 25.
Statements
Case 10 To 12 'TestExpression is between 10 and 12.
Statements
Case 4,7,9 'TestExpression is 4,7 or 9.
Statements
Case Else 'TestExpression is anything else.
Statements
End Select
Case statements are usually more concise and readable than the equivalent If-Then-Else
structure. As with any decision structure, there is only one outcome; make the tests in
the correct order i.e. is x greater than 10? Followed by is x greater than 5? Not the
reverse.
In the following example, the value of the variable x determines the value of the variable
y. If x is 250 or more then y is "Large", if x is from 50 to 249 then y is "Medium" and for
any other value y is "Small":
Sub CaseStatement()
x = 100
Select Case x
Case Is >= 250
y = "Large."
Case 50 To 249
y = "Medium."
Case Else
y = "Small."
End Select
End Sub
Choose function
Selects and returns a value from a list of arguments.
Choose(index, choice1, choice2, etc.)
Where index is a numeric expression that results in a value between 1 and the number of
available choices. Choose returns a value from the list of choices based on the value of
index. If index is 1, Choose returns the first choice in the list; if index is 2, it returns the
second choice, and so on. If index is not a whole number, it is rounded to the nearest
whole number before being evaluated.
Page 7
Excel 2010 Visual Basic for Applications
Example
The message box displays the second item in the list:
Sub Main()
x = 2
y = Choose(x, "Tom", "Dick", "Harry")
MsgBox y
End Sub
Switch Function
Evaluates a list of pairs of expressions and values and returns the value associated with
the first expression in the list that is True.
Switch(expr1, value1, expr2, value2, etc.)
The expressions are evaluated from left to right but can be entered in any order.
Example
The message box displays "STG", the value associated with the x="UK" expression:
Sub Main()
x = "UK"
y = Switch(x = "UK", "STG", x = "USA", "USD", x = "DEN", "DKK")
MsgBox y
End Sub
Decision making code is a matter of personal taste and judgement. Generally speaking,
If-Then-Else is the most flexible, Case Statements are best where you are testing one
expression over many different conditions, the CHOOSE function is best for processing
sets of numbers and SWITCH is best for substitution.
In the following example, all four methods are demonstrated. An organisation has a
financial year that starts in April and we need to take the current calendar month value
and convert it into the current accounting month value; April is 1 etc. The x variable
stores the current month as returned by the Month and Date functions and we have to
calculate the value of the MonthNo variable:
x = Month(Date)
Page 8
Excel 2010 Visual Basic for Applications
Looping
When a process has to be repeated it is best to use a loop structure to make sections of
instructions repeat rather than have multiple sets of duplicated instructions.
Conditional Loops
Repetition while a certain condition is satisfied or until a certain condition is satisfied.
Check for the condition before running the loop:
Do While condition
Statements
Loop
Execute the commands once before checking the condition:
Do
Statements
Loop While condition
Use the keywords Until or While to define the condition, placing them either at the top or
at the end of the Do…Loop.
Sub DoLoops1()
x = 10
Do Until x > 40
x = x + 10
MsgBox x
Loop
End Sub
Sub DoLoops2()
x = 10
Do
x = x + 10
MsgBox x
Loop While x < 40
End Sub
Counter Loops
Iterating a loop for a specific number of repetitions:
Sub ForNextCounterLoop1()
For i = 1 To 5
MsgBox "The counter value is " & i
Next
End Sub
Page 9
Excel 2010 Visual Basic for Applications
Sub ForNextCounterLoop2()
End Sub
Implementing the structure on Excel objects, a loop to protect every worksheet in the
workbook:
Sub ForNextCounterLoop3()
End Sub
You can conditionally break out of a For...Next loop using Exit For. Loops can contain
other loops, this is called nesting. There is no need to restate the loop counter variable
after the Next keyword; usually it is only used to identify the ends of nested loops:
For i=1 To 10 'Exterior loop.
Statements
For j=1 To 5 'Interior loop.
Statements
Next j
Next i
Collection Loops
For iterating a collection; either a collection of objects in Excel or a collection in memory:
For Each Element In Collection
Statements
Next
Where Element represents one of the items in Collection. Element is a variable. The
collection is either a defined Excel Collection Object or is a container reference. There is
no need to explicitly reference each element; it is implicit to the collection and the
variable is used to represent each element on each iteration of the loop.
In the first example the Collection is the Worksheets Collection; the loop goes through
each member of the Collection. In the second example the Collection is defined as a
range of cells; a range contains cells so the loop goes to each one in turn. In neither case
do you have to do make the object reference in the code, the loop does the referencing
for you. The Worksheets Collection is a defined Collection Object in Excel, whereas in the
second example the range reference is a container, a reference to a set of like objects.
Sub ForEachCollectionLoop1()
Page 10
Excel 2010 Visual Basic for Applications
Sub ForEachCollectionLoop2()
Objects are either singular or Collection objects. Collections are sets of like objects.
There is a Worksheets Collection object and it has certain Properties, like its Count
property, which is the number of Worksheets in the Collection. Each Worksheet is a
member of the Worksheets Collection but it is also an individual Worksheet object and
has, in turn, its own particular Properties, like its Name property
To calculate the number of Pivot Tables on the worksheet:
x = ActiveSheet.PivotTables.Count
Objects have associated Methods and Properties. Methods are actions that they can
perform. Properties are their particular attributes. Most Properties are variable properties
and you can change them by specifying a new value. Every statement in VBA code that
manipulates a part of Excel must take the following form:
Object.Property or Object.Method
You must start with the Object reference. The object reference can either be specific or
non-specific.
Non-specific Object Reference
Assign the red Fill colour to every cell on the active worksheet:
ActiveSheet.Cells.Interior.ColorIndex = 3
or
Cells.Interior.ColorIndex = 3
Page 11
Excel 2010 Visual Basic for Applications
Object.Method statements are rather different as they can accept additional required or
optional arguments. The following statement copies A1:A50 to the Clipboard using the
Copy method.
Range("A1:A50").Copy
The Copy method has an optional argument, Destination. Using this you can specify
where you want to directly copy the cells, avoiding the Clipboard. There is a space
character required between the Method and the argument value.
Range("A1:A50").Copy Destination:= Range("A100")
You can leave out the argument descriptor and just give the value but there must always
be a space character between the Method and the value.
Range("A1:A50").Copy Range("A100")
For a fuller discussion on argument specification see By Name, By Order page 76
Application Object
Workbooks Collection
Workbook Object
Worksheets Collection
Worksheet Object
Page 12
Excel 2010 Visual Basic for Applications
Square brackets
The full object reference to the worksheet cell A1 is Range("A1"). If you are typing-in cell
references rather than recording, it is easier to use the shortcut notation using square
brackets, [A1]. You can use the same style of referencing on other objects as well, such
as worksheets but there are a number of rules and restrictions.
It is usually best to restrict the square bracket notation to cell references only, where it is
entirely definitive and reliable.
With…End With
The With statement is used so the object reference can be made and then retained so
that multiple actions may be carried out without having to repeat the same object
reference in each statement.
You can keep the With reference open for as long as you like in the same procedure, just
pointing to it using the dot operator. Every With requires an End With. You can have
multiple With pointers. When you are reading code that uses multiple With pointers, the
rule is simple; the dot points to the nearest With.
With Object
.Property
With .Child Object
.Method
.Method
End With
End With
Page 13
Excel 2010 Visual Basic for Applications
Recording a macro
Turn on the macro recorder by clicking the Developer
tab, Code group, Record Macro control or View Tab, The Macros group
Macros Group, Macros control and choose Record in the View tab.
Macro from the pop-up.
Choose where you want to store the module and fill in the
Macro name and Shortcut key boxes. Turn off the
recorder using the Stop Recorder control when you have
finished. Do not leave the recorder turned on.
Controls for turning the macro recorder on and off are also located
down the bottom of the Excel application window, on the Status Bar
immediately after the Mode indicator.
It is rather difficult to see what type of selection you are recording as the caption always
reads "Use Relative References" regardless of the state of the control.
You get an Absolute reference recorded when the control's background is not coloured-in,
so when you click on cell B5 the recording returned is:
Range("B5").Select
When the control's background is coloured-in the recording is Relative, so when you click
the cell below the active cell the recording returned is:
ActiveCell.Offset(1, 0).Range("A1").Select
So, you record specific cell selection using the Select method of the Range object and the
Range property to specify the cell. Or you can record relative cell movement and
selection using the Offset property and the Range property of the Range object.
For cell movement the Range("A1") expression is redundant and can be removed. For
relative cell selection this Range property is more useful, the following recording means,
starting one cell down from the active cell, select an area three columns wide by four
rows deep. In other words, treat the offset from the active cell as position A1.
ActiveCell.Offset(1, 0).Range("A1:C4").Select
Page 14
Excel 2010 Visual Basic for Applications
Macro buttons
You need an easy way of triggering your procedures from an Excel worksheet and macro
buttons are one of the most popular choices. To create a macro button you can use
either the Button control from the Form Controls collection or the Command Button
control from the ActiveX Controls collection.
Both collections are located in the Developer tab, Controls
group, Insert control.
There is little to choose between the two controls as they perform
exactly the same task, it is a matter of personal taste.
Form Controls were designed and built for Excel and are by far
the easiest to implement whereas ActiveX Controls are universal
graphic objects that are available in most MS Office applications.
Use the Button control if you are not sure which one to use but
do not hesistate to use the Command Button control if you
already familiar with using ActiveX controls.
Right-click the Macro button to adjust its properties. This button is a non-printing object
by default.
Page 15
Excel 2010 Visual Basic for Applications
You can also open the Customize the Quick Access Toolbar dialog by clicking File
tab, Excel Options, Quick Access Toolbar.
Page 16
Excel 2010 Visual Basic for Applications
You do not have the same flexibility to create menus and toolbars in Excel 2010 as you
had in earlier versions. Menus and Toolbars created by macros in these versions are
displayed on the Add-Ins tab when you open the workbook and run the macros.
Page 17
Excel 2010 Visual Basic for Applications
This is an illustration
of the custom tabs
and custom groups
created.
The context of the
tab can be set by
choosing between
Main Tabs and Tool
Tabs.
Security
It is quite easy to write a computer virus using VBA and have it run automatically when
the workbook is opened. Use Excel’s security settings to prevent these problems. Click
the Macro Security control in the Developer tab to check the current settings.
Trusted locations
Probably the best way to handle macro security is to designate one or more folders as
trusted locations. All the workbooks in a trusted location are opened without a macro
warning. You can designate trusted folders in the Trusted Locations section of the
Trust Center dialog box.
Page 18
Excel 2010 Visual Basic for Applications
Page 19
Excel 2010 Visual Basic for Applications
And here is the final version with meaningful comments and indentation:
'Enter XYZ down the column.
With ActiveCell
.Offset(0, 0) = "X"
.Offset(1, 0) = "Y"
.Offset(2, 0) = "Z"
End With
There is no right way of writing code so allow your solution to follow your own thought
process. There are two distinct styles: Concrete where the process follows the physical
world, selecting cells and moving around, and Abstract which is a simpler style using
numbers and indices. The recorded example is in the concrete style; type-in an entry,
move down one cell, type-in another entry etc. The optimised version more abstract;
write X into the current cell, Y in the cell below and Z into the cell below that.
Toggles
A Toggle is a statement that switches from one state to another and the standard
construction can be applied to any Property that accepts a True / False value.
The following recorded statement turns off the display of Headings.
ActiveWindow.DisplayHeadings = False
After editing the statement now toggles the display of Headings.
ActiveWindow.DisplayHeadings = Not ActiveWindow.DisplayHeadings
Optimised:
With Columns("E:E")
.Columns.AutoFit
.Style = "Comma"
End With
Sub Macro1()
Range("C3:E8").Select
Application.PrintCommunication = False
With ActiveSheet.PageSetup
.PrintTitleRows = ""
.PrintTitleColumns = ""
End With
With ActiveSheet.PageSetup
Page 20
Excel 2010 Visual Basic for Applications
.PrintHeadings = False
.PrintGridlines = False
.PrintComments = xlPrintNoComments
.PrintQuality = 600
.CenterHorizontally = False
.CenterVertically = False
.Orientation = xlLandscape
.Draft = False
.PaperSize = xlPaperA4
.FirstPageNumber = xlAutomatic
.Order = xlDownThenOver
.BlackAndWhite = False
.Zoom = 100
End With
Application.PrintCommunication = True
ActiveWindow.SelectedSheets.PrintOut Copies:=1, Collate:=True, _
IgnorePrintAreas:=False
End Sub
The code for printing macros can be quite dramatically reduced. The PrintOut Method is
all you need for printing, in the usual form, Object.Method:
Sub ConcisePrintMacro()
End Sub
Printing and Page Setup settings are like this:
Sub PageSetupSettings()
With ActiveSheet.PageSetup
.CenterFooter = "My Report"
.RightFooter = "by Anon E. Mouse"
.Orientation = xlLandscape
.FitToPagesWide = 1
.FitToPagesTall = 1
End With
Range("A1:G250").PrintOut
End Sub
You sometimes need to print out a named range of cells. To make Page Setup settings
you need to identify the worksheet that owns the range. Use the Parent property of the
range rather than making an explicit reference to the worksheet. The Parent property of
an object points back up the containment hierarchy to identify the object above.
Page 21
Excel 2010 Visual Basic for Applications
Sub IdentifyParentSheetOfNamedRange()
With MySheet.PageSetup
.CenterFooter = "My Report"
.RightFooter = "by Anon E. Mouse"
.Orientation = xlLandscape
.FitToPagesWide = 1
.FitToPagesTall = 1
End With
MyRange.PrintOut
End Sub
Copying
This again, is a reduction of recorded code.
Sub RecordedCopyAndPaste()
Range("C4:E11").Select
Selection.Copy
Sheets("Sheet2").Select
Range("D7").Select
ActiveSheet.Paste
Application.CutCopyMode = False
End Sub
[B1] = [A1] 'An assignment statement; this copies the cell display…
Page 22
Excel 2010 Visual Basic for Applications
Identify the first row and column in the block containing the active cell:
i = ActiveCell.CurrentRegion.Row
j = ActiveCell.CurrentRegion.Column
Select from cell C3 to the top of the current region:
Range("C3").End(xlUp).Select
Select from cell C3 to the last cell on the right in the current region:
Range("C3").End(xlToRight).Select
ActiveCell.EntireColumn.Select
ActiveCell.EntireRow.Select
If your macros incorporate extensive moving and selecting you might consider creating a
Move object to make your macros easier to create. See Creating a Move object page 80.
End Sub
Page 23
Excel 2010 Visual Basic for Applications
Without using the SpecialCells Method the procedure would have been far harder to write
requiring a loop to examine each worksheet cell and a conditional test to see whether the
cell contained a number that was not a formula, as follows:
For Each Cell In ActiveSheet.UsedRange
If Cell.HasFormula = False And IsNumeric(Cell) = True Then
Cell.Clear
End If
Next
Note that SpecialCells is a Method of the Range Object therefore the following line of
code would fail:
ActiveSheet.SpecialCells(xlCellTypeConstants, 1).Select
Manipulating cells
The Cells property can replace A1 references or offsets to manipulate cells.
The Cells property returns the Range Object, every cell on the entire worksheet:
Cells.NumberFormat = "General"
Manipulating cells with R1C1 coordinates, using a loop counter to make cell references:
Sub CopyValues()
For r = 2 To 100
Select Case Cells(r, 1)
Case 1
Cells(r, 2).Copy Cells(r, 3)
Case 2
Cells(r, 2).Copy Cells(r, 4)
Case 3
Cells(r, 2).Copy Cells(r, 5)
Case 4
Cells(r, 2).Copy Cells(r, 6)
Case Else
Cells(r, 2).Copy Cells(r, 7)
End Select
Next
End Sub
This style of code is entirely abstract but very concise and direct. Notice how easy it is to
get the idea of going down to the next row on a worksheet by using the incrementing
counter variable of a For…Next loop rather than the clumsy Offset, Select statements.
You can display R1C1 references on an Excel worksheet by choosing File tab, Options,
Formulas, Working with formulas, R1C1 Reference Style.
Application Settings
Here are some useful Application Property settings that can speed up execution time. As
the Application Object (Excel itself) is the top-level object you could enter these without
using the Application object reference.
Switching between automatic and manual recalculation:
Application.Calculation = xlCalculationAutomatic
Application.Calculation = xlCalculationManual
Page 24
Excel 2010 Visual Basic for Applications
Block all input from the keyboard and mouse except for interactive elements displayed by
the procedure:
Application.Interactive = False
Most of the above will need to be reset to their normal states at the end of the
procedure. Be particularly careful with the Interactive property. Make absolutely sure
that you set its value to True before the end of the procedure otherwise Excel will not
accept any user input after the macro has been executed.
Code Window
Press F7. This is where you view the code, the actual instructions contained in the
Module. The Code Window has two views, Procedure View and Full Module View.
Procedure View shows only one procedure at a time, Full Module View lists all the
procedures in the module, separated by ruler lines. To change the view, use the buttons
situated at the lower left-hand corner of the window.
At the top of the window are two drop-down lists, the one on the right-hand side is the
Procedure List. Use this to navigate from one procedure to another. Or use the keyboard
shortcuts Ctrl+PgUp/Ctrl+PgDn. The left-hand list is the Object list.
You will also notice the standard code colours: Blue for Keywords, Green for Comments
and Black for everything else. Try not to change the colours unless the Blue is indistinct
from the Black on your monitor or if you suffer from Red/Green colour vision problems.
Change the colours using Tools, Options, in the Editor Format tab.
Context Help
To look up the relevant page in the documentation, click an expression in the Code
Window and press the F1 key.
Complete Word
One of the most useful features of the
Code Window is Complete Word. These
are drop-down Autolists that enable
statement completion showing those
Objects, Methods, Properties and Events
that are available in context. The lists
appear as soon as you start typing. To
accept an item from the list and stay on
the same line to continue your statement,
press TAB.
Page 25
Excel 2010 Visual Basic for Applications
The lists significantly reduce the number of typing errors. To start up the lists without
typing an initial expression, press Ctrl+Spacebar. Or right-click the relevant line and
choose Complete Word.
Commenting/ Uncommenting
The apostrophe is the Remark character, remarks or comments are entirely ignored when
the code is run. Comments are used for explanation and annotation of the process code.
Comments can be entered at any position in the Module. There is no end comment
character; everything following the apostrophe is a comment.
Every procedure should have at least one comment. Code is updated and revised
periodically during its lifetime. It is very difficult trying to interpret uncommented code.
You can add a comment at the end of the code line; you do not need to start a new line.
Selection.NumberFormat = "0.00" 'Set number format
Commenting out is a technique where sections of code are temporarily disabled for
testing purposes only to be reinstated once the testing is completed. It is extremely
tedious to comment out each separate line. You will find the Comment Block and
Uncomment Block tools on the Edit toolbar.
The easiest way to set or remove Breakpoints is to click on the left-hand grey margin of
the code window. Break Mode is when you can see the Yellow indicators, Reset to return
to Design Mode. The Reset tool is on the Standard toolbar.
Errors
Unless you can record all your macros you will always get some kind of error as you
develop your code. There are three types of error, Logical errors, Syntax errors and
Run-Time errors. Choose Debug, Compile the Project to check for errors.
A Logical error is where the code does not fail but does not do what you wanted. You will
always get an error message for the other types of errors. Syntax errors are coloured
red. Run-Time errors do not arise as you type-in your code, only when you run the
procedure. Always Debug a Run-Time error. The Debug Button switches the Module to
Break Mode and identifies the statement that caused the error. It does not correct the
Page 26
Excel 2010 Visual Basic for Applications
statement. The entire Module is compiled when you run a procedure, the Run-Time error
is not necessarily in the current procedure. Reset when you have fixed the error.
Syntax Errors
Syntax error, clearly there is something wrong:
Selection.SpecialCells(xlCellTypeVisible select
A syntax error is usually a minor error in
typing or construction; a comma missing,
brackets not closed etc. Syntax errors
rarely cause serious problems.
The standard colour for Syntax errors is
red.
Run-Time errors
Run-Time error, there is something wrong but it is not obvious:
Selection.SpecialCells(x1CellTypeVisible).Select
Line Continuation
Some statements are rather lengthy and difficult to read on one line. Do not press enter
to wrap the text; this just produces a syntax error. To continue the same logical line onto
the next physical line, introduce a line continuation character into your code.
Use the following sequence of keystrokes for a line continuation character; Spacebar,
Underscore, Enter. It is a sequence, not a key combination. You can have as many line-
continuations as you require. Second and subsequent lines can be tabbed.
Statements like this can be rather difficult to read:
ActiveWorksheet.Cells.SpecialCells(xlCellTypeVisible).Select
Page 27
Excel 2010 Visual Basic for Applications
Properties Window
Press F4. The Properties Window is where you set the variable properties of objects. Not
of much use for developing code in General modules. It is extensively used when
designing graphical User Forms.
The Properties Window can be irritating for the first few
occasions when you use it. It always displays the variable
properties of the active selection and you may find
yourself looking down the listings in the property pages
and being unable to find the property that you are looking
for. Check the active selection, it is so easy to change the
selection and not realise it.
Most of the property page values can be selected from
drop down lists but sometimes they have to be typed-in.
To register a typed value, either press ENTER or click
another cell on the property page. Do not click outside
the window as this usually just changes the selection.
Note that there are two tab sections which classify all the
properties; Alphabetic and Categorised.
The Properties window is usually displayed by default in the VB Editor at the lower left
hand corner. Do not hesistate to close the window if you find it intrusive, you can always
open it when it is required.
Page 28
Excel 2010 Visual Basic for Applications
Object Browser
Press F2. If the macro recorder is the
phrasebook for VBA then the Object
Browser is the dictionary.
All references are listed here. Choose
the top drop-down list to reference
the relevant library, Excel or VBA?
If you have an idea of the name of
something that you are trying to look
up, enter an expression into the
Search box below to perform a
freeform search of the database.
If you just want to see a full listing of
what is available then choose an item
from the Classes list on the left hand
side and examine the Members list on
the right hand side.
It can take some time to find what
you are looking for in the Object
Browser but there is no alternative if
you do not know its name.
Locals Window
This window is used for viewing
the current values of all the
variables currently in Scope.
Step Into your code and see the
exact state of any variable at any
point in the procedure.
Watch Window
The Watch Window is
similar to the Locals
Window but is used
to view the current
values of only
certain, nominated
variables.
You need to specify the Watch expressions using Add Watch on the Debug menu.
Page 29
Excel 2010 Visual Basic for Applications
Immediate Window
Press CTRL+G. The Immediate
Window is used for immediate
execution of a single
expression. Type the
expression into the Window
and press enter to execute it.
If the expression returns a
value then it needs to print
the result to the Window.
Precede your expression with a question mark in order to print the result to the window.
Use this Window to experiment with statements. You can write a log to the Immediate
Window by including Debug.Print statements in your procedure.
Set a bookmark by choosing Edit, Bookmarks, Toggle Bookmark. Then choose Next
Bookmark and Previous Bookmark to navigate. Bookmark shortcuts are on the Edit
toolbar.
Page 30
Excel 2010 Visual Basic for Applications
Variable Declaration
The Dim statement is used to declare variables either in a single line or listing form.
Explicitly declared variables are available in the Complete Word lists. Dim is short for
Dimension (which makes no particular sense unless the variable is an array, a variable
that can have more than one dimension). You can place the Dim statement anywhere in
the procedure, so long as you declare the variable before you use it. It is a convention to
list declaration statements at the start of the procedure.
Dim x, y, z
or
Dim x
Dim y
Dim z
Option Explicit
Sub Main()
Dim x, y, z
x = 50
y = 100
z = Application.Average(x, y)
MsgBox z
'View variable values in the Locals Window.
End Sub
Data Types
You can also declare the Type of data you intend to store within a Variable or Constant.
This will ensure you use only the memory required to hold the data and validate the
data. It will also cause problems if you do it incorrectly.
If you do not specify a data type, the Variant data type is assigned by default.
The Data Type is declared in the same statement as the variable or constant itself.
Dim MyVar As String
Const MyNum As Integer = 5
You can also use one declaration statement for several variables:
Dim MyVar As String, MyNum As Integer
However, when using a single declaration statement, you must declare the Data Type for
each variable. In the following example, only one variable has a defined Data Type, the
other is Variant.
Dim MyVar, MyNum As Integer
Page 31
Excel 2010 Visual Basic for Applications
'Initialisation:
x = 50000
y = 1.5
MsgBox y
z = "Fred"
Page 32
Excel 2010 Visual Basic for Applications
Procedure Scope
A variable / constant with Procedure level scope is not available to any other procedure
within the Module unless it is passed in a subroutine call. Use a Dim statement in the
Sub.
Sub Main()
MyVariable = 50
MyOtherVariable = 100
End Sub
Sub Main2()
End Sub
Page 33
Excel 2010 Visual Basic for Applications
are used for this process. VBA calls this an Object Variable. You must use the Set
keyword to initialise an Object Variable. Do not use Set for any other purpose.
Sub ObjectVariables()
Dim x As Integer
Dim c As Range
Set c = ActiveCell
End Sub
The use of the Let keyword in assignment statements is a matter of personal style. Some
authors like to use it as it explicitly shows that the statement is a variable assignment
statement. However, there is a fundamental difference between Let and Set.
Set x = Range("A1:D25")
This statement creates the Object Variable, x that can then be used as an alias for the
cell range. Any actions carried out on x are immediately reflected back to the cells.
Let x = Range("A1:D25")
This statement creates the Array Variable, x which stores the current values of the cells
in memory. Any actions carried out on x do not affect the cells. The cell values and the
variable values are entirely separate entities.
End Sub
Page 34
Excel 2010 Visual Basic for Applications
The principal benefit of defining the Class of the object in your declaration is that the
Complete Word lists will pop up when you type in the identifier, this does not occur when
you use the generic type Object. So, it is well worth the extra effort to define the Class
correctly, you can use the Locals window if you are not sure but usually all you would
ever need are the primary classes; Range for a cell or range of cells, Worksheet for a
worksheet and Workbook for a workbook.
When you have finished using the Object Variable in your code but the procedure is going
to continue to execute statements you can release the memory allocated to the variable
and destroy the object variable by setting its value to Nothing.
Set MyObjVar = Nothing
Use of Constants
A Constant is a value in a procedure that does not change. Constants are similar to
Variables; the key difference is that the values of variables can change during execution,
whereas the values of constants are fixed.
Unlike variables, constants are both declared and initialised in one statement.
Sub ConstantsVsVariables()
'Declaration.
Dim USD As Currency
'Initialisation.
USD = 1.80
End Sub
Naming Conventions
A one or three character lower case prefix is commonly added to variables as a document
convention. Variable identifiers are then readily recognised in the code and are easier to
enter; explicitly declared variables are available in the Complete Word drop-down lists.
The process of explicit type declaration is known as Casting. Identifiers often use the
Hungarian convention where a variable name starts with a group of lower-case letters
which are mnemonics for the type or purpose of that variable, followed by the main
identifier where the first character is capitalised. This practice of producing compound
words with medial capitals is known as CamelCase.
Page 35
Excel 2010 Visual Basic for Applications
Functions
Function procedures accept, manipulate and then return values. They can be used in
conjunction with Sub procedures to perform utility tasks in your code and perform in a
similar manner to subroutine calls.
More commonly in Excel, Function procedures are used to bundle complex calculations
into a central procedure or to design user-defined functions. You do not run Function
procedures; they are called. In VBA code a function is called in the same way as a VBA
function. In worksheet cells a function is called in the same way as an Excel function
In your code you can call existing functions from VBA, see Calling VBA Functions on page
36 and also Excel Worksheet Functions, see Calling Excel Functions on page 37
You can also write Function Procedures in VBA to interact with your Sub procedures, see
Creating Function Procedures on page 37, or as User Defined Functions for use in
Worksheet formula expressions, see Creating a custom function for Excel on page 37
Page 36
Excel 2010 Visual Basic for Applications
Page 37
Excel 2010 Visual Basic for Applications
Excel formulas have to use awkward linear conditional statements whereas VBA has
superior structures. It is far more efficient to use a simple expression in your worksheet
cells to call a complex calculation than it is to have multiple copies of a complex formula.
Function RATIO(First_Number, Second_Number)
'Accepts : Values from two worksheet cells.
'Returns : Simple ratio to 0 decimal places.
x = First_Number
y = Second_Number
If x = y Then
RATIO = "Parity"
ElseIf x > y Then
RATIO = Round(x/y, 0) & ":1"
Else
RATIO = "1:" & Round(y/x, 0)
End If
End Function
To call the RATIO function you would enter the following expression into a worksheet cell,
replacing the argument names with cell references:
=RATIO(First_Number, Second_Number)
However, to call the function from a cell in another workbook you would need an external
reference to the workbook containing the function procedure:
=BookName!RATIO(First_Number, Second_Number)
Creating an Add-In
To make a Function or a Sub procedure global and visible to all workbooks make an Excel
Add-In. This is a compiled version of the code in the file that is loaded automatically as
the Excel application is opened. To make an Add-In:
Step 1 (Optional)
Document the Add-In. Should you skip this step when you create an Add-In only the
Name of the Add-In file is shown in the Add-In Manager list and there is no Help
documentation in the Paste Function dialog box.
Documenting the Add-In in the Add-In Manager listing:
Attach Summary properties to the file. File tab, Info, Properties. Fill-in the Title and
Comments boxes. (these are used for the Caption and Description text respectively in
the Add-In Manager list)
You may need to click Show All
Properties to open out the view of
all the document properties.
Page 38
Excel 2010 Visual Basic for Applications
Step 2
Create the Add-In file.
File tab, Save As, Other Formats, Save As
Type = Excel Add-In (*.xlam)
Step 3
Set the Add-In Manager to load the Add-In file as
Excel starts up.
Developer tab, Add-Ins group, Add-Ins.
Click Browse and select the .xlam file
from the file listings. Make sure that the
check box is checked.
All the procedures in the current project
are included in the Add-In. Add-Ins can
contain Subs or Functions or both. The file
properties entered earlier will now be visible,
otherwise just the file name is displayed.
Protecting a Project
Even the code for an Add-In is available in the VB Editor so to prevent tampering, lock
the Project with a password. Choose Tools, VBA Project Properties, Protection tab.
Events
The role of event driven procedures
Worksheet and Workbook events trigger your code automatically when a specific event
occurs, such as opening a file or recalculating a worksheet. The Event procedures already
exist as code shells. All you need to do is find them and fill in the shell.
Page 39
Excel 2010 Visual Basic for Applications
To disable the automatic execution of the Workbook_Open event, hold down the SHIFT
key as you open the file.
MsgBox "Hello"
End Sub
On Methods
These are Methods of the Application object and have the same effect as events but are
implemented in a different way. You need two procedures: one to schedule the event in
the memory, the other is the procedure that is called when that event occurs.
OnKey Method
Runs a specified procedure when a particular key or key combination is pressed.
This example assigns My_Procedure to the key sequence CTRL+PLUS SIGN and assigns
Other_Procedure to the key sequence SHIFT+CTRL+RIGHT ARROW.
Application.OnKey "^{+}", "My_Procedure"
Application.OnKey "+^{RIGHT}", "Other_Procedure"
Page 40
Excel 2010 Visual Basic for Applications
OnTime Method
Schedules a procedure to be run at a specified time in the future (either at a specific time
of day or after a specific amount of time has passed).
This example runs My_Procedure 45 seconds from now:
Application.OnTime Now + TimeValue("00:00:45"), "My_Procedure"
This example cancels the OnTime setting from the previous example:
Application.OnTime EarliestTime:=TimeValue("17:00:00"), _
Procedure:="My_Procedure", Schedule:=False
The following procedures are stored in Personal.xls and guarantee that you will not forget
to go home on time:
Sub Auto_Open()
End Sub
Sub HomeTime()
End Sub
The following procedures saves the active workbook automatically every 30 minutes.
Sub AutoSaver()
End Sub
Sub SaveWorkbook()
ThisWorkbook.Save
Call AutoSaver
End Sub
Page 41
Excel 2010 Visual Basic for Applications
User Interaction
Message Box
The MsgBox function can be used in either its Statement or Function forms.
Statement form
This is the simplest form, used for non-interactive messaging. You do not need
parentheses around the arguments:
MsgBox "Hello Charlie"
The prompt text in the message does not wrap onto a new line
in the box until the character count reaches 160; meanwhile
the box just gets wider with the text on one line. Use any one
of the following constant values to force a new line:
Chr(10),Chr(13), vbCrLf, vbCr, vbLf
(This is quite a different idea to code line continuation using Spacebar, Underscore,
Enter. This is for forcing new lines of text in Message Boxes and Input Boxes)
Forcing new lines in the prompt:
MsgBox "Hello Charlie," & vbCrLf & "have a nice day."
See overleaf for a discussion of the arguments accepted by the MsgBox function. See By
Name, By Order page 76 for instructions on how to specify them.
Function Form
You must use the Function form when you are interacting
with the user. You need to store their response. The
Function form requires the arguments in parentheses; you
are entering an assignment statement.
The message box returns a result based on which button
as clicked then this returned result is evaluated.
Sub Main()
Else
MsgBox "Data will not be deleted.", _
Buttons:=vbExclamation, _
Title:="Data Retained"
End If
End Sub
Page 42
Excel 2010 Visual Basic for Applications
Return Values
Constant Value Description The return value is only generated when the
vbOK 1 OK MsgBox function is used in its function form and
vbCancel 2 Cancel depends upon which command button was clicked
vbAbort 3 Abort when the message box was dismissed.
vbRetry 4 Retry You can use either the value or the constant in
vbIgnore 5 Ignore your code to determine which button was clicked.
vbYes 6 Yes
vbNo 7 No
Page 43
Excel 2010 Visual Basic for Applications
Input Boxes
You can use either the generic VBA Input Box function or the Excel Application object's
Input Box Method. The InputBox Method allows for some entry validation using its
optional Type argument and is the only one where you can point out of the box to select
a range of cells on a worksheet. Invalid data entry into Excel’s Input Box is handled by
the Excel application.
0 Formula The Type argument specifies the return data type. It can
1 Number be one or a sum of the values shown in the table.
2 Text Only the Excel InputBox Method allows you to point out of
4 True or False the box to return a range reference, in the example
8 Cell reference return data type 8 is specified and the input box will
16 Error value accept a range reference either by typing or dragging
64 An array of values through the cells:
Sub ExcelInputBoxMethod()
MyRange.Interior.ColorIndex = 3
End Sub
Page 44
Excel 2010 Visual Basic for Applications
When you assign a variable value using an Input Box never set the data type before the
input has been received and validated. To avoid Type Mismatch errors, declare the
variable as Type Variant and then use Type conversion functions after the input has been
captured and validated.
In the following example the USD variable has to be of Type Currency. Had the initial
declaration been As Currency then the code would produce a Type Mismatch error when
the Input Box received invalid data and before the input could be evaluated in the loop.
Sub MisMatchErrors()
Dim USD As Variant
Do
USD = InputBox("Enter the USD rate:")
Loop Until IsNumeric(USD) = True
USD = CCur(USD)
MsgBox USD
End Sub
Most of the work involved in coding Input Boxes is in the validation of the received input.
In the following example, we must specify the current month as a two-digit string.
Sub DataValidation()
Dim vMonthNo As Variant
End Sub
If your Input Box is prompting for an entry into a worksheet cell then consider an easier
alternative to writing a macro, like Data Validation.
Page 45
Excel 2010 Visual Basic for Applications
The Caption property is the text that appears in the title bar of the main Microsoft Excel
window. If you do not set a name, or if you set the property to Empty, this property
returns "Microsoft Excel".
Application.Caption = "The date today is " & Date
Sub MakeMyToolBar()
Dim cBar As CommandBar
Dim cControl As CommandBarControl
'Create toolbar.
Set cBar = Application.CommandBars.Add
cBar.Name = "MyToolbar"
'Add a control.
Set cControl = cBar.Controls.Add
With cControl
.FaceId = 23
.OnAction = "MyMacroMark1"
.TooltipText = "My Fantastic Macro"
End With
Continues overleaf.
Page 46
Excel 2010 Visual Basic for Applications
Page 47
Excel 2010 Visual Basic for Applications
End Sub
Page 48
Excel 2010 Visual Basic for Applications
Shortcut Menus
You can add a macro shortcut to any of the shortcut menus (or right-click menus) You
must identify the correct menu, here is a list of the primary shortcut menus:
Worksheet Cell ...............CommandBars("Cell")
Worksheet Tab ...............CommandBars("Ply")
Worksheet Column ......... CommandBars("Column")
Worksheet Row ..............CommandBars("Row")
This example modifies the cell shortcut menu, adding a new item at the end of the menu,
"Tick mark". When you select the menu item you run the "Tickmarks" macro.
Sub AddToCellShortCutMenu()
Dim MyBar As CommandBar
Dim MyControl As CommandBarButton
Page 49
Excel 2010 Visual Basic for Applications
Sub ShowExcelFileOpen()
Dim ReturnValue As Boolean
ChDir "C:\My Documents"
ReturnValue = Application.Dialogs(xlDialogOpen).Show("*.*")
If Not ReturnValue Then
MsgBox "Cancelled"
End If
End Sub
All the constants used to identify the relevant dialogs are preceded with xlDialog and you
can find a list of them in the Object Browser. Choose View, Object Browser and select
Excel from the Project/Library drop-down list (upper-left hand corner) In the Search Text
drop-down list (just below the previous one) type "xlDialog" and click the Search button.
For file operations where you are prompting the user to provide valid file names, folders
and paths for opening and saving files it is usually more convenient to use the
GetOpenFilename and GetSaveAsFilename methods and the Show method of the
FileDialog object in preference to the built-in dialogs.
GetOpenFilename Method
This method displays the Excel File Open dialog ensuring that you obtain a valid filename
and path. It does not open the file; it returns the filename as a string. You can then do
whatever is required with the filename. You can set file filters if required. The method
returns FALSE if the dialog is cancelled.
The following example displays the Open dialog and then opens the selected file. Notice
how the "MyFile" variable is declared as type Variant. When the dialog is cancelled the
variable contains a Boolean (FALSE), otherwise it contains a String.
Sub GetMyFileName()
Dim MyFile As Variant
MyFile = Application.GetOpenFilename()
GetSaveAsFilename Method
This method displays the Excel Save As dialog box and returns a valid path and filename.
It does not save the file; it returns the filename as a string. The method returns FALSE if
the dialog is cancelled.
Sub GetMyFileSavingName()
Dim MyFileName As Variant
Dim MyNewBook As Workbook
Page 50
Excel 2010 Visual Basic for Applications
Page 51
Excel 2010 Visual Basic for Applications
User Forms
Display interactive dialogs in the Excel interface by including a User Form in your project.
The programming of User Forms can be time-consuming as every action that the User
Form performs has to be coded, for example, the OK button does not do anything until
you write the code contained in its click event.
You need to be familiar with User Form objects, there is no macro recorder here. The
User Form object model is zero-based, the first item in a list is item 0. Excel is one-
based. There are potential mismatch problems.
Step by Step
If any of the interface elements mentioned below are not visible then choose them from
the View Menu.
1. Select your project in the Project Explorer Window and use the Insert menu to
insert a User Form.
2. Use the Toolbox to draw the required Controls on the User Form. Drag to resize
the Form or its contained Controls as necessary. Use the usual Drag and Drop
techniques to copy or move the Controls—drag to move, CTRL drag to copy.
3. Set the Name properties of your controls as soon as you have drawn them. It is
important that you do this early on as it can prove impossible to register them
later on and you are stuck with the default Names. Use the Properties Window to
set any other properties that are static, such as Captions.
Some Form properties are static and are done at Design Time, others are dynamic
and will be changed as the user manipulates the Form. These are done in code at
Run Time.
4. In your General Module (use the Insert menu to insert a Module if necessary)
enter the code to show the User Form at the relevant point in your procedure.
UserFormName.Show
Use the Close box on the Form to close it; you will notice that clicking the OK
button at this stage has no effect.
5. Now expose the User Form’s Object Module and complete the Events for each
Form element. Click the View Code tool or press F7 or double-click any one of the
Controls.
You will find that during this design process that you will have numerous windows open
in the VB Editor and you may find yourself getting confused and loosing track of what
you were trying to do. Persevere, you do get used to it. But there is no magic wand, you
have to get used to all the different views and windows. There is the window containing
the User Form object which has two views; the code view and the object view, there is
the Properties window and there is the Controls Toolbox.
Page 52
Excel 2010 Visual Basic for Applications
Page 53
Excel 2010 Visual Basic for Applications
buttons in the User Form. None of the controls would be visible to the General module at
this point if the Form had already been unloaded.
In the first example, the Click Events of the OK and Cancel buttons change the value of a
Public variable and then unload the Form. The Public variable is still in scope after the
Form has been destroyed and is therefore available for evaluation in the General module.
General Module Code User Form Object Module Code
Public GlobalVar As Integer Private Sub cmdOK_Click()
GlobalVar = 1
Sub Main() Unload Me
GlobalVar = 1 End Sub
frmDemo.Show
Select Case GlobalVar Private Sub cmdCancel_Click()
Case 1 GlobalVar = 0
'OK button Unload Me
Case 0 End Sub
'Cancel button
End Select
End Sub
In the second example the User Form is only hidden, not unloaded by the OK and Cancel
button Click Events. The Form remains in scope with its control values visible to the main
process code in the General module. The relevant decisions based on its control values
are made and then finally the Form is unloaded. Form Controls have a non-specific
property, Tag which can be used to store a control value.
General Module Code User Form Object Module Code
Private Sub cmdOK_Click()
Sub Main() With Me
frmDemo.Show .cmdOK.Tag = True
Select Case frmDemo.cmdOK.Tag .cmdCancel.Tag = False
Case True .Hide
'OK button End With
Case False End Sub
'Cancel button
End Select Private Sub cmdCancel_Click()
Unload frmDemo With Me
End Sub .cmdOK.Tag = False
.cmdCancel.Tag = True
.Hide
End With
End Sub
But the code is still not completed, as we have not yet handled the situation where the
user has closed the User Form by clicking the Form’s Close Box instead of using the
Cancel button. In this case, the form is unloaded but none of the code associated with
the Cancel button is executed; as the Click event has not occurred. Here, we must use
the Form’s QueryClose event to specify the precise meaning of the Close Box.
Having to consider all the nuances of the User Form’s events makes coding User Forms a
chore but it is the only way to achieve a robust application.
A User Form in your Project means that you have more than one code module to deal
with. It is good practice to follow the convention of organising your code so that the main
process of execution is in the General Module and the code in the User Form Module is
restricted to the manipulation of the Form.
Naming Conventions
It is awkward having to use the default object names when you are completing the event
procedures for each control; is the OK button CommandButton1 or is it
CommandButton2? Follow the published standard conventions for Control names, add
the three-character lower case prefix to your names and you will never have any
problems identifying your control objects in code.
Page 54
Excel 2010 Visual Basic for Applications
Remember to name your controls as they are created and before you run the Form, you
may not be able to rename then retrospectively.
Object Prefix Give the controls obvious names;
Check Box Chk remember that when you are writing
Combo Box Cbo the code for the controls you will not
Command Button Cmd be able to see the User Form. For
Frame Fra example, good names for the OK and
Label Lbl Cancel buttons are 'cmdOK' and
'cmdCancel'. All the control names will
List Box Lst
be available in the Complete Word
Option Button Opt
listings so the more organised and
Text Box Txt
consistent the naming convention is
Toggle Button Tog the easier the code will be to write.
User Form Frm
Page 55
Excel 2010 Visual Basic for Applications
End Select
ExtractRegionalDataCLOSE:
Exit Sub
End Sub
Page 56
Excel 2010 Visual Basic for Applications
.lblRegion.Caption = _
"Extract data for " & g_strRegionSelected
End With
End Sub
End Sub
List Boxes
In the previous example the list in the List Box was populated from static values in the
code using the AddItem method. This is not always appropriate and you may need to fill
the list with values from worksheet cells. Use the RowSource property of the List Box to
specify the cell values required but do not try to use an object reference; only an
external formula reference is accepted.
If you are setting the property value in the Properties Window then the following style of
reference should be used:
=Sheet1!A1:A12
If you are setting the property value in your code then the statement should be like this:
Me.NameOfListBox.RowSource = "=Sheet1!A1:A12"
The following example we are unable to specify the cell range for a list box definitively as
the list is dynamic and constantly changing. Use the CurrentRegion property to find the
list and then the Address property to reveal the cell references of the list.
Private Sub UserForm_Initialize()
Dim SheetName As String
Dim SourceRange As String
SheetName = ActiveSheet.Name
SourceRange = Range("A1").CurrentRegion.Address
Me.lstDynamic.RowSource = _
"=" & SheetName & "!" & SourceRange
End Sub
Page 57
Excel 2010 Visual Basic for Applications
Design the Form by drawing all the control objects required and then hide or reveal them
or change their positions as necessary. The following example shows a succession of two
User Forms, both are completely different but are the same base Form object, frmDemo.
Public g_sTypeOfForm As String
End Sub
Code in the User Form Object Module
The code is quite long and repetitive but is easily generated by copying. Execution of the
code is rapid; it is certainly no slower to build Form controls through code than it is to
have them preset. The memory overhead of extra lines of code in a module is
significantly less than that of multiple User Forms.
Using Me
You will have noticed from the examples the use of the keyword, Me to return the
reference to the User Form object itself. This should only be used in the code contained
Page 58
Excel 2010 Visual Basic for Applications
in the User Form module, it is out of scope in the General module. It can be omitted as
the top level object in the User Form is, of course, the User Form itself.
For example, to return the reference to the User Form, frmDataEntry. In the General
module, the reference would have to be explicit:
frmDataEntry.Show
However, in the Object module, the reference would either be explicit:
frmDataEntry.Caption = "Step 1 of 2"
Or use Me:
Me.Caption = "Step 1 of 2"
Or be entirely implicit:
Caption = "Step 1 of 2"
Dimensioned Arrays
Page 59
Excel 2010 Visual Basic for Applications
'or
End Sub
Array Subscripts
Arrays are created when a variable is declared with a dimensional subscript value and
can be single dimensioned or multi-dimensional. Arrays can have up to 60 dimensions.
The data type is common to the entire array, although type Variant is acceptable. Arrays
only need to be declared to the dimensions of the data that they will hold, beware of
eating up memory by over-sizing your arrays.
This statement declares an array of ten elements:
Dim MyList(1 To 10)
End Sub
Page 60
Excel 2010 Visual Basic for Applications
MyArray = Sheets(1).Range("A1:B6")
Dynamic Arrays
A dimensioned array has to be declared using a constant value, however this constant
value maybe unknown at the point of declaration. Use ReDim instead of Dim to create a
dynamic array; one that can be re-sized at run time.
Sub DynamicArray()
End Sub
In the previous example you will have noticed that we had to repopulate the array after
having resized it. ReDim resizes the array but clears the data already stored. Use ReDim
Preserve when you want to resize an array but retain the data previously stored.
ReDim Preserve is particularly useful when you want to gather some information and
store it in an array but do not know the extent of the data. In the following example a
range of cells is being searched, we want to store the cell references of the cells
containing a certain value.
As the data is found, it is stored in the array and then an extra element is added to the
array ready for the next item of data. When the search is completed the array has one
element too many; this is then removed.
Note the use of ReDim at the start of the procedure to initialise the array variable, this
has to be done so that the UBound function can calculate the size of the array when the
first element of data is stored.
Sub DynamicArrayOnTheFly()
Page 61
Excel 2010 Visual Basic for Applications
End If
Next
End Sub
GoTo MyLineLabel
MyLineLabel:
End Sub
Error_Handler:
Select Case Err.Number
Case 55 '"File already open" error.
Close #1
Case Else
GoTo Procedure_Exit
End Select
Page 62
Excel 2010 Visual Basic for Applications
This statement moves to the next statement in the procedure and ignores the error:
On Error Resume Next
This statement disables the current error handler in the procedure. If the procedure is a
subroutine then the error is handled by the calling procedure:
On Error GoTo 0
You can set as many error statements as you require but only one is current.
Sub IgnoringAllErrors()
On Error GoTo 0
End Sub
The Err Object can be used to give you specific details on the current error, using the
following properties:
Err.Number
Err.Source
Err.Description
You will find that the Err object's Number property will reset under certain conditions,
assign its current value to a variable in order to produce reliable validation code.
Here is a standard template for arranging error-handling code. Notice how the error
handler is isolated from the main process by terminating the procedure prematurely
using the Exit Sub statement. You only want the error handler code to execute if an error
actually occurs.
Page 63
Excel 2010 Visual Basic for Applications
Sub ErrorHandlerTemplate()
Dim x As Integer
'Cause an error.
x = 50000
ErrorHandler:
MsgBox "An unexpected error occurred, " & Err.Description
Resume Next
End Sub
It is quite in order to have the error handler call another procedure passing the current
error values for evaluation. Many different procedures can then all use the same central
error handler procedure.
ErrorHandler:
Call CentralErrorHandler(Err.Description, Err.Number, Err.Source)
Page 64
Excel 2010 Visual Basic for Applications
To create a new PivotTable we can use the Add and CreatePivotTable methods of the
PivotCaches object:
ActiveWorkbook.PivotCaches.Add(SourceType:=xlDatabase, SourceData:= _
"Sheet1!R1C1:R87C6").CreatePivotTable TableDestination:="", _
TableName:="PivotTable1", DefaultVersion:=xlPivotTableVersion10
The SourceData is a range object containing the data for the report, the TableDestination
is where the report is returned. The TableName and other arguments are optional.
For example, define the source data as being all the data from A1 on the active
worksheet:
Set rngSource = ActiveSheet.Range("A1").CurrentRegion
The table destination is a new worksheet in the workbook, inserted after the active
sheet:
Set wksSales = Worksheets.Add(After:=ActiveSheet)
And create the PivotTable, naming it as 'Sales Report':
ActiveWorkbook.PivotCaches.Add _
(SourceType:=xlDatabase,SourceData:=rngSource) _
.CreatePivotTable TableDestination:= wksSales.Range("A1"), _
TableName:="Sales Report"
Create an object variable to refer to the pivot table report:
Set ptSales = wksSales.PivotTables("Sales Report")
Now, add the fields required. Every column in the source data range creates a member of
the PivotFields collection as the Pivot cache contains all the source data. But to show a
field in the report you have to use the AddFields method:
ptSales.AddFields RowFields:="Country", ColumnFields:="Month"
Specifing them as:
PageFields:= "Product"
RowFields:= "Country"
ColumnFields:= "Month"
To specify two or more fields with the same orientation it is like this:
ColumnFields:= Array("Month","Country")
Data Fields
To add a data field to the report you do not use the AddFields method, rather you set the
Orientation property of an existing pivot table field to xlDataField (this field does not
have to be one of those already added, it can be any of the pivot fields):
ptSales.PivotFields("Units").Orientation = xlDataField
However, it is not possible to predict the name of the new pivot field as Excel names it
automatically depending on the default Summary function. If the default Summary
function is Sum then it is called "Sum of Units", if the default function is Count then it is
called "Count of Units". And, at this stage there is no way of finding out what the default
Summary function is! Once you have named the field Excel will not change it again
automatically but you need to make sure that you can specify the summary function
correctly.
Either, refer to the field not as a member of the PivotFields collection (where it is
contained but you do not know what it is called) but as a member of the DataFields
collection. As you create a data field it becomes the first member of this collection, the
next data field is the second member etc.
ptSales.PivotFields("Units").Orientation = xlDataField
ptSales.DataFields(1).Function = xlSum
ptSales.DataFields(1).Name = "Total Sales"
Page 65
Excel 2010 Visual Basic for Applications
Or, set all the relevant properties as you create each data field, like this:
With ptSales.PivotFields("Units")
.Orientation = xlDataField
.Caption = "Total Sales"
.Function = xlSum
.NumberFormat = "#,##0_-"
End With
With ptSales.PivotFields("Units")
.Orientation = xlDataField
.Caption = "Units %"
.Calculation = xlPercentOfTotal
End With
Excel Charts
Excel Charts are one of the most complicated sections in the Object Model. The hierarchy
of an individual Chart object is fairly obvious, the principal issue is to access the Chart
object itself. You can use the ActiveChart property for the current chart but identifying a
specific chart can be a problem.
Chart Objects
Excel has two types of chart, a chart on a chart sheet or an embedded chart in a
worksheet. There is no ChartSheet object, the Charts property of the Application object
returns a Sheets collection containing one Chart object for each chart sheet. It does not
contain the Chart objects for the embedded charts.
In the case of the embedded charts, the Chart object is not contained directly in the
worksheet. Rather, the worksheet contains a ChartObject object that is a container for
the Chart object. Confused? In practice it means that you have to include .Chart in the
object reference for the Chart elements, like the axes but not for the Chart area.
Thus, the object reference for the chart sheet, "Chart1" is as follows:
ThisWorkbook.Charts("Chart1")
Whereas, the reference for "Chart 1" on "Sheet1" is:
Worksheets("Sheet1").ChartObjects("Chart 1").Chart
It is advisable to examine your recordings carefully and experiment using the Immediate
Window before starting your code. Embedded charts in particular.
An object reference like this for the first chart on the worksheet will fail:
ChartObjects(1).Name
You must return the Sheet object and the Chart object:
ActiveSheet.ChartObjects(1).Chart.Name
The following procedure creates an embedded chart.
Sub CreateEmbeddedChart()
Dim MyChart As ChartObject
Dim c As Long
Dim r As Long
Page 66
Excel 2010 Visual Basic for Applications
With MyChart
'Define the Chart type.
.Chart.ChartType = xlLine
End With
End Sub
With oWSht.ChartObjects(i)
End With
Page 67
Excel 2010 Visual Basic for Applications
Next
End Sub
'User prompt.
sPrompt = "This macro breaks the link between your charts" & _
" and the data on which they depend." & vbCr & _
"Do you want to continue?"
'Action cancelled.
If iAns = vbNo Then GoTo ExitChartConstants
Page 68
Excel 2010 Visual Basic for Applications
With Application.WorksheetFunction
End With
Next oSeries
Next oChrt
Next oWSht
'Confirm completion.
MsgBox "Chart formulas are converted.", vbInformation
ExitChartConstants:
Exit Sub
ErrChartConstants:
sPrompt = "The following unexpected error occurred: " _
& vbCrLf & _
Err.Description & _
"." & " Error Number: " _
& Err.Number & vbCrLf & _
"Chart not converted." & vbCrLf & _
"Click OK to continue."
Resume Next
End Sub
Page 69
Excel 2010 Visual Basic for Applications
On Error GoTo 0
'Force a zero-length string to Empty.
If sFormulaString = "" Then
DerivedValues = Empty
Exit Function
End If
End If
End Function
Page 70
Excel 2010 Visual Basic for Applications
Application Interaction
All MS Office applications are automation clients and servers so that you can use VBA as
a bridge language to interact with the services provided by other applications.
Late Binding
Use the CreateObject or GetObject functions to return an object reference. This gives you
a late bound interface meaning that as you write your code in Excel you will not be able
to look up Help for the other object model or use statement completion. Here is a late
bound instance of MS Word:
Sub UsingWordLateBinding()
End Sub
Early Binding
Add a reference to
your project using
the References
dialog. In the VB
editor menu choose
Tools, References.
Page 71
Excel 2010 Visual Basic for Applications
Finally, write the code required to manipulate Word. You will see all of the relevant
documentation in the Object Browser and the Word Object Library references are
available in the Complete Word drop down lists. Again, you have to make the other
application visible if you want to see it on your screen. Your code is far more efficient if
you do not display the visual interface. However, it is a good idea to have the other
application visible while testing your code.
With wdWordSel
.TypeText "Have a nice day"
.WholeStory
.Font.Name = "Arial"
.Font.Size = 12
.Font.Bold = wdToggle
End With
wdWordDoc.PrintOut
wdWord.Quit
'Destroy objects.
Set wdWordSel = Nothing
Set wdWordDoc = Nothing
Set wdWord = Nothing
Exit Sub
ErrorHandler:
MsgBox "Unexpected error. " & Err.Number
End Sub
Page 72
Excel 2010 Visual Basic for Applications
This is the type of code required to automate Excel from another application:
Sub ExcelAutomationEarlyBinding()
With oXLWSht
.Cells(1, 1) = "Tom"
.Cells(1, 2) = "Dick"
.Cells(1, 3) = "Arry"
End With
oXLApp.Visible = True
oXLApp.Quit
End Sub
Dim rs As Recordset
Dim ReturnVal As Integer
Set rs = _
DBEngine.OpenDatabase("c:\db1.mdb"). _
OpenRecordset("ClosingPrices")
End Sub
You can omit the column and row values to return the entire Recordset. In the example,
the value of the ReturnVal variable is not being used for any specific purpose, you would
usually use the variable for validation purposes. Copying begins at the current row of the
Recordset object. After copying is completed, the EOF property of the Recordset object is
set to TRUE.
Page 73
Excel 2010 Visual Basic for Applications
Send Keys
If the application that you want to use in your code does not have a programmable
interface then use a combination of Shell and SendKeys to interact with it.
Sub RunCalculator()
End Sub
Composer As String
Title As String
Opus As Integer
End Type
Sub Report()
Dim MusicTitle As Music
Dim msg As String
Page 74
Excel 2010 Visual Basic for Applications
MusicTitle.Opus = 9
MsgBox msg
End Sub
Enumerations
You will notice from recorded macros that VBA uses a number of internal constants to
identify key values. This makes the code much easier to read. Constant identifiers such
as vbYes or xlLandscape are easier to implement and interpret than their actual values.
You can declare your own enumeration variables where you would otherwise have to use
numeric constants. For example, fill colours have to be specified as index values in your
current colour palette. It is difficult to remember the corresponding number for each
colour.
Enumeration variables are declared at the module level with an Enum statement. The
elements of the Enum type are initialised to constant values using either positive or
negative numbers.
Enum MyFillColours
Red = 3
Green = 43
Yellow = 6
Blue = 49
End Enum
Sub Main()
End Sub
By Reference, By Value
Variables may be passed from one procedure to another By Reference or By Value using
the statements ByRef or ByVal. All arguments are passed to procedures by reference,
unless you specify otherwise.
Passing By Value sends a copy of the original variable. Changes to the argument within
the procedure are not reflected back to the original variable. Passing By Reference gives
direct access to the variable. The statement is made by the calling procedure. Data types
must be consistent.
Passing variables to a subroutine. In the following example the variables x and y are
passed to the subroutine Sub2 when it is called by Main. x is passed By Reference and y
is passed By Value. The subroutine manipulates the two variables locally but when the
flow of control returns to Main the value of the y variable is unchanged.
Page 75
Excel 2010 Visual Basic for Applications
The same rules apply for passing argument values to a function procedure.
Sub Main()
Dim x As Integer
Dim y As Integer
x = 50
y = 100
Call Sub2(ByRef x, ByVal y)
MsgBox x & y
End Sub
x = x + 10
y = y * 2
End Sub
Declare the relevant Data Type for the received values in the subroutine otherwise they
are stored locally as Variants. The Data Type received must match the Data Type passed.
By Name, By Order
Understanding named and optional argument values. When you call a Sub or Function
procedure, you can supply arguments by order, in the order they appear in the
procedure's definition, or you can supply the arguments by name without regard to
position. Arguments are either optional or required.
The methods of Excel’s objects are internal procedures and the same rules apply. For
example, the Worksheets object has an Add method that has four optional parameters.
(You can see these as you type; press the spacebar after Add and the syntax diagram
appears, optional parameters are contained in square brackets)
Worksheets.Add([Before],[After],[Count],[Type])
To add three sheets after the first sheet using the By Name convention:
Worksheets.Add After:= Worksheets(1), Count:= 3
or
Worksheets.Add Count:= 3, After:= Worksheets(1)
To add three sheets after the first sheet using the By Order convention:
Worksheets.Add ,Worksheets(1), 3
To add three sheets after the first sheet using a combination of both conventions:
Worksheets.Add ,Worksheets(1), Count:= 3
A named argument consists of the argument name followed by a colon and an equals
sign (:=), then followed by the argument value. Never use just the equals sign.
Named arguments are especially useful when you are calling a procedure that has
optional arguments. If you use named arguments, you do not have to include commas to
denote missing positional arguments. Using named arguments makes it easier to read
your code.
The parenthesis are only required when you are using the function form to return a value
to a variable. In the following example, omitting the parenthesis around the "After"
argument would produce a syntax error:
Dim MyNewSheet As Worksheet
Page 76
Excel 2010 Visual Basic for Applications
Classes
Classes define objects. Every Excel object is an instance (a copy) of a particular Excel
Class. A worksheet object is an instance of the Worksheet Class. Classes are object
templates containing their collection of methods and properties. In our VBA procedures
we use the Excel objects created for us and rarely need to create our own.
However, for complicated and difficult code structures it is sometimes useful to take an
object-orientated approach by creating our own code objects, which are supersets of the
existing Excel objects. This will promote simplicity and easier maintenance of the code
contained in general modules by allowing us to re-use rather than repeat fragments of
code that are frequently required.
Creating an Object
To create your own object you need a Class Module to contain the property and method
definitions. Then an instance of the Class creates the object.
For example, we want to create a MyWbk object to use in our procedures in a general
module. The object will have a Save method that does not actually save the workbook
but instead sets the Saved property of the workbook to TRUE. The object will also have a
set of read-only properties listed in the table below:
Property Name Data Returned
PathName The full file name and path.
BookName The workbook name with the .xls extension removed.
NonBlanks Count of the workbook’s cells containing formulas or constants.
The file name and path is directly available as an existing Excel property but the other
two are rather more specialised requiring the manipulation of existing properties and we
want to be able to retrieve the data without repeating the code every time it is required.
Page 77
Excel 2010 Visual Basic for Applications
Then you return to your general module to create an instance of the class, clsMyWbk by
declaring a Public variable of the specific Class Type and using the New keyword.
The object, MyWbk is of Type clsMyWbk (as defined by the clsMyWbk Class) and we can
access its associated methods and properties using the usual Object.Method or
Object.Property syntax in our code. Object references are available in Complete Word.
Code in the General Module
Public MyWbk As New clsMyWbk
Sub Main()
MsgBox MyWbk.NonBlanks
MsgBox MyWbk.BookName
MsgBox MyWbk.PathName
MyWbk.Save
End Sub
The object only exposes its Public properties and procedures and the internal workings of
the Class, how these property values were calculated, are hidden. The object is a
container for a collection of properties and procedures. This is the theory of
encapsulation where complex Private procedures are available through a simpler
interface of Public methods and properties.
In the following example we need to set and reset various Excel application and
document settings in our procedures. Instead of using a series of subroutine calls, we
create a Class, 'clsAppSet' to contain all of our settings, create the object, 'AppSet' and
then simply apply them by using the Methods of the object.
Page 78
Excel 2010 Visual Basic for Applications
When you need the same procedures again for another Project, just insert a copy of the
entire Class module.
Page 79
Excel 2010 Visual Basic for Applications
Page 80
Excel 2010 Visual Basic for Applications
Page 81
Excel 2010 Visual Basic for Applications
Page 82
Excel 2010 Visual Basic for Applications
File Operations
File operations can be incorporated into your macros by using the statements of the VBA
File System Class.
For example
Create a new directory on the current drive. MkDir "Data"
End Sub
Page 83
Excel 2010 Visual Basic for Applications
'Initialise.
Let Data = ""
Let FirstRecord = True
Next
End Sub
Make sure the text file exists before you attempt to write data to it. It is quite in order to
use an application like Windows Notepad to create a text file containing no data. The text
output into the file would appear like this:
"UK ,North ,Soap ,1789 ,81460
,Jan ,PR960001 , " etc.
Page 84
Excel 2010 Visual Basic for Applications
Calender control
In this example, column D on
the worksheet has to have
dates entered into the cells.
When you select a cell in the
column a Calendar control
appears, you specify the date
and it is entered into the active
cell.
Draw the control on the
worksheet and then right-click
the sheet tab and choose View
Code. Enter the following event
procedures:
Private Sub Calendar1_Click()
ActiveCell.Value = ActiveSheet.OLEObjects("Calendar1").Object.Value
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'If ActiveCell is in column D align control to cell and show.
If ActiveCell.Column = 4 Then
With ActiveSheet.OLEObjects("Calendar1")
.Top = ActiveCell.Top
.Left = ActiveCell.Offset(0, 1).Left
.Visible = True
End With
Else
'Otherwise hide the control.
ActiveSheet.OLEObjects("Calendar1").Visible = False
End If
End Sub
This example is exactly the same as the previous but
uses a Check Box control. The object names are all
shown in the Object list (top right hand side) of the
sheet module.
This example shows a list box when the cell is selected,
the list box contains a list of currencies. As you select a
currency the corresponding exchange rate is entered into
the active cell. The ListFillRange property of the control
refers to a range of cells on the worksheet containing
foreign exchange data.
Page 85
Excel 2010 Visual Basic for Applications
When you have finished setting all the control object properties, click the Design Mode
control (Set square, ruler and pencil) to activate the controls. Please note that it is also
possible to achieve similar interactive effects in worksheet cells by using the Data
Validation control in the Data Tools group on the Data tab. Less sophisticated but
much easier.
Sub MyGetUserName()
Dim Buffer As String * 25
Dim ReturnValue As Long, UserName As String
End Sub
The user name is retrieved into the variable 'Buffer', which is a 25 character length
string. Any unnecessary characters are then stripped out. All the WIN API functions have
to be used in the function form, so you need to assign the function to a variable, in this
case the variable 'ReturnValue'. The value of the variable has no particular use other
than to test whether the function has failed or not.
* Please note that this is merely an illustration of using the WINAPI GetUserName
function, should you actually need to return the user name then use the following Excel
property:
Application.UserName
There are a number of books available on the WIN API and you can also search in the
Microsoft Knowledge Base. The information that you need to find is the name of the
function required, how to properly declare the function and (hopefully) an example that
you can copy.
Page 86
Excel 2010 Visual Basic for Applications
Case Studies
Case Study 1. Using the Personal Workbook
Recording a macro in the Personal Macro Workbook to hide error values in worksheet
cells. A Custom Menu Item in Excel’s Format menu triggers the macro.
Sub HideErrorValues()
Selection.Font.ColorIndex = 2
Selection.NumberFormat = "[Black] General"
End Sub
Intended to hide divide by zero errors (#DIV/0!) the macro will hide all cell error values
by changing the Font colour to white and forcing numbers to Black in the General
Number Format. To be really effective the macro should be more sophisticated and take
into account the existing cell number format and font colour.
[A2].Select
End Sub
[D1].Select
x = ActiveSheet.UsedRange.Rows.Count
For i = 1 To x
Call Finder
.StatusBar = Format(i / x, "0%") & " Complete."
Next
.ScreenUpdating = True
.StatusBar = False
End With
End Sub
Page 87
Excel 2010 Visual Basic for Applications
End Sub
End Sub
x = ActiveSheet.UsedRange.Columns.Count
[A1].Select
For i = 1 To x Step 2
With ActiveCell
.ColumnWidth = 10
.Offset(0, 1).ColumnWidth = 5
.Offset(0, 2).Select
End With
Next
End Sub
Sub AlternateColumnsAbstract()
x = ActiveSheet.UsedRange.Columns.Count
For i = 1 To x Step 2
Columns(i).ColumnWidth = 10
Columns(i + 1).ColumnWidth = 5
Next
End Sub
Page 88
Excel 2010 Visual Basic for Applications
Sub AlternateColumnsOddEven()
x = ActiveSheet.UsedRange.Columns.Count
For i = 1 To x
If i Mod 2 = 0 Then
'Column number is even.
Columns(i).ColumnWidth = 5
Else
'Column number is odd.
Columns(i).ColumnWidth = 10
End If
Next
End Sub
In the last procedure we needed to determine if a column number was an even number.
We tested for modulo 2, is the number divisible by 2, leaving a remainder of zero? The
modulus, or remainder operator, Mod is invaluable for any type of interval calculation.
For example, performing a certain action every fifth iteration of a For...Next loop.
End Sub
Page 89
Excel 2010 Visual Basic for Applications
Sub ExactlyTwelveSheetsIfThenElse()
Dim iNumShts As Integer
Dim i As Integer
Const TARGET_SHTS As Integer = 12
End Sub
Sub ExactlyTwelveSheetsDoLoop()
Dim iNumShts As Integer
Dim i As Integer
Const TARGET_SHTS As Integer = 12
End Sub
Sub DeleteThenInsert()
Dim i As Integer
Application.DisplayAlerts = False
'Delete all sheets except for one.
For i=1 To Worksheets.Count-1
Worksheets(1).Delete
Next
'Then add 11 to make 12.
Worksheets.Add Count:= 11
End Sub
Page 90
Excel 2010 Visual Basic for Applications
x = 1.54
y = 5000
NewSht = Worksheets.Add(After:=Worksheets(1))
MyArea = Worksheets(1).UsedRange
End Sub
Corrected:
Sub Main()
Dim x As Double
Dim y As Integer
Dim NewSht As Worksheet
Dim MyArea As Range
x = 1.54
y = 5000
Set NewSht = Worksheets.Add(After:=Worksheets(1))
Set MyArea = Worksheets(1).UsedRange
End Sub
x = Application.Sum(Row_Totals)
y = Application.Sum(Column_Totals)
If x <> y Then
CheckSum = "BADSUM!"
Else
CheckSum = x
End If
End Function
Page 91
Excel 2010 Visual Basic for Applications
g_intSheetIndex = 1
g_bolLandscape = True
g_bolPrintReport = False
frmPrintReport.Show
With Worksheets(g_intSheetIndex)
With .PageSetup
If g_bolLandscape Then
.Orientation = xlLandscape
Else
.Orientation = xlPortrait
End If
End With
.PrintOut
End With
End Sub
Page 92
Excel 2010 Visual Basic for Applications
End Sub
g_intSheetIndex = lstWorksheets.ListIndex + 1
g_bolPrintReport = True
Unload Me
End Sub
End Sub
Page 93
Excel 2010 Visual Basic for Applications
With Application
.ScreenUpdating = False
.EnableCancelKey = xlDisabled
End With
'Initialise objects.
Set oTargetBook = ThisWorkbook
Set oTargetSheet = oTargetBook.Worksheets(1)
Set oMatchRange = oTargetSheet.Range("CountryNames")
Set oTargetRange = oTargetSheet.Range("DataTable")
Page 94
Excel 2010 Visual Basic for Applications
'Destroy Objects.
Set oSourceRange = Nothing
Set oSourceSheet = Nothing
Set oSourceBook = Nothing
Next vRegion
'Destroy Objects.
Set oTargetRange = Nothing
Set oMatchRange = Nothing
Set oTargetSheet = Nothing
Set oTargetBook = Nothing
'Confirmation message.
MsgBox "Updates for " & Format(Date, "dddd d MMMM yyyy") _
& vbCr & "were sucessfully completed.", _
Buttons:=vbInformation, Title:="Data Updated"
With Application
.ScreenUpdating = True
.StatusBar = False
End With
End Sub
Page 95
Excel 2010 Visual Basic for Applications
Sub RefreshData()
Dim wSheet As Worksheet
Dim pTable As PivotTable
With Application
.DisplayStatusBar = True
.StatusBar = "Refreshing Pivot Tables..."
For Each wSheet In Worksheets
For Each pTable In wSheet.PivotTables
pTable.RefreshTable
Next
Next
.StatusBar = False
End With
Call Auto_Open
End Sub
Page 96
Excel 2010 Visual Basic for Applications
'Form cancelled.
Unload frmMatcher
'Terminate macro.
GoTo UnMatchedItems_Exit
Case True
'Initialise Objects.
Set wksMatch = Worksheets(g_BaseSheet)
Set wksTo = Worksheets(g_CompareSheet)
Set wksReport= _
Worksheets.Add(After:=Worksheets(Worksheets.Count))
Page 97
Excel 2010 Visual Basic for Applications
'Destroy objects.
Set rngCell = Nothing
Set rngRecordID = Nothing
Set rngCopy = Nothing
Set rngDestination = Nothing
Set rngMatch = Nothing
Set rngTo = Nothing
Set wksMatch = Nothing
Set wksTo = Nothing
Set wksReport = Nothing
End Select
Exit Sub
UnMatchedItem:
UnMatchedItems_Exit:
End Sub
Page 98
Excel 2010 Visual Basic for Applications
'Validation test #4. That the row header is found in the compare sheet.
Let bHeaderFound = False
Let iColCount = _
Worksheets(g_CompareSheet).Cells(1).CurrentRegion.Columns.Count
For i = 1 To iColCount
If m_MatchDescription = Worksheets(g_CompareSheet).Cells(1, i) Then
Let bHeaderFound = True
Let g_CompareColumnNumber = i
Exit For
End If
Next
Page 99
Excel 2010 Visual Basic for Applications
Exit Sub
cmdOK_Click_Exit:
MsgBox strErrorMessage, vbCritical + vbOKOnly, "Invalid Input"
End Sub
lstHeaderRow.Clear
For i = 1 To iColCount
lstHeaderRow.AddItem Worksheets(g_BaseSheet).Cells(1, i)
Next
End Sub
Private Sub lstCompare_Click()
Let g_CompareSheet = lstCompare.Text
End Sub
Private Sub lstHeaderRow_Click()
Let g_MatchColumnNumber = lstHeaderRow.ListIndex + 1
Let m_MatchDescription = lstHeaderRow.Text
End Sub
Page 100
Excel 2010 Visual Basic for Applications
Handy Macros
Protecting All the Worksheets in a Workbook
The password is optional, just delete it from the macro if it is not required.
Public Sub ProtectAllWorksheets()
Dim Wsht As Worksheet
End Sub
To reverse the process and clear the protection, change the line to:
Wsht.Unprotect Password:="Secret"
To protect only certain worksheets in the workbook but leave the others unprotected,
introduce a decision making construction into the loop. The following example protects
only "Sheet1" and "Sheet3" in the workbook.
Make sure that you enter the actual name of the worksheet into the code; "Sheet1" and
"Sheet3" are not valid if you have renamed the worksheets.
Public Sub ProtectCertainWorksheets()
Dim Wsht As Worksheet
End Sub
End Sub
Page 101
Excel 2010 Visual Basic for Applications
Formulas to Constants
Reducing all the formulas in a workbook to constants usually involves a tedious series of
Copy and Paste Special, Values commands. This macro processes the entire workbook in
a few seconds by overwriting the formulas with the cell values. NB This version does not
process array formulas, they remain untouched.
Public Sub FormulasToConstants()
Dim wksWorksheet As Worksheet
Dim rngFormulas As Range
Dim rngCell As Range
Const ALL_FORMULAS As Integer = 23
Next wksWorksheet
End Sub
Page 102
Excel 2010 Visual Basic for Applications
'Loop.
For Each rngCell In rngCells
If IsDate(rngCell) Then
Let intDay = Day(rngCell)
Let intMonth = Month(rngCell)
Let intYear = Year(rngCell)
Let DateValue = intMonth & "/" & intDay & "/" & intYear
rngCell.Value = DateValue
End If
Next
Exit_DateDDMMSwitcher:
End Sub
Errors to Zeros
Changing normal formulas to conditional formulas to force a zero value when the formula
returns an error value. You select the cells with the formulas and the macro wraps a
conditional structure around the original formula. For example, if the original formula in
the cell was =A1/B1, after the macro has been run the formula will be as follows:
=IFERROR(A1/B1,0)
The IFERROR function is only available with Excel 2007/2010; should you need to work
with earlier versions of Excel then substitute the equivalent IF/ISERROR construction:
=IF(ISERROR(A1/B1),0,A1/B1)
Both versions are shown in the code listing.
Public Sub ForceToZero()
Dim rngSelected As Range
Dim rngFormulas As Range
Dim Cell As Range
Dim strPrompt As String
Dim strFormula As String
'Loop.
For Each Cell In rngFormulas
'Remove the equals sign.
Let strFormula = Mid(Cell.Formula, 2)
End Sub
Page 103
Excel 2010 Visual Basic for Applications
End Sub
End Function
Page 104
Excel 2010 Visual Basic for Applications
Index
Page 105
Excel 2010 Visual Basic for Applications
Page 106