Professional Documents
Culture Documents
VBA
Message &
Input Boxes
A Comprehensive Guide to Using VBA
Message Boxes and Input Boxes
By Martin Green
VBA Message Boxes
Contents
About This Book .......................................................................................................... 4
About the Exercises ..................................................................................................... 4
Message Boxes ........................................................................................................... 5
The Anatomy of the Message Box.................................................................................. 5
Message Box Title ................................................................................................... 5
Message Box Icons.................................................................................................. 6
Message Box Buttons .............................................................................................. 6
Programming Message Boxes........................................................................................ 8
The MsgBox Method for Simple Messages .................................................................. 9
Step-by-Step: A Simple Information Message ........................................................ 9
Multi-line Messages ............................................................................................... 10
Step-by-Step: A Multi-Line Message ................................................................... 11
The MsgBox Function for Multi-Button Messages ....................................................... 14
Step-by-Step: Evaluating a Yes/No Response with an If Statement......................... 14
Evaluating a Yes/No/Cancel Response with a Case Statement ................................ 17
Setting the Default Button ................................................................................. 18
Using the Help Button ........................................................................................... 18
Modal Message Boxes............................................................................................ 19
Writing Long Messages .......................................................................................... 20
Including Data in Messages .................................................................................... 21
Coping with Quote Marks ....................................................................................... 22
Being Creative with Titles ...................................................................................... 23
Using Constants for Consistency ............................................................................. 23
Using Numbered Items and Bullet Points ................................................................. 24
Things You Can't Do with a Message Box ................................................................. 26
Input Boxes.............................................................................................................. 27
The Anatomy of the Input Box................................................................................ 27
Programming Input Boxes .......................................................................................... 29
The VBA InputBox Function .................................................................................... 29
Accepting Input from the User ........................................................................... 29
Checking the User's Response ............................................................................ 30
Let the User Try Again ...................................................................................... 33
What If the User Cancels? ................................................................................. 34
Supplying a Default Value.................................................................................. 35
Excel's InputBox Method........................................................................................ 36
Declaring a Data Type for the Input Box Value ..................................................... 37
If the User Enters the Wrong Data Type .............................................................. 38
If the User Cancels the Input Box ....................................................................... 39
Working with Input Formulas (Type 0) ................................................................ 39
Working with Input Numbers (Type 1) ................................................................ 40
Working with Input Text (Type 2) ....................................................................... 41
Working with Logical Values (Type 4).................................................................. 41
Working with Cell References (Type 8) ................................................................ 42
Working with Error Values (Type 16)................................................................... 44
Working with Arrays of Values (Type 64) ............................................................. 45
Step-by-Step: Exploring Message Boxes ...................................................................... 49
Part 1: Prepare the Workbook ................................................................................ 49
Part 2: Write the Basic Macro ................................................................................. 49
Part 3: Add a Confirmation Message........................................................................ 50
Part 4: Test the Macro ........................................................................................... 51
Part 5: Add a Timer............................................................................................... 51
Part 6: Add Statistics to the Confirmation Message ................................................... 52
Part 7: Let the User Choose the Minimum Number .................................................... 53
Part 8: Add an Error Handler .................................................................................. 55
Final Code Listing for the MessageDemo Macro ......................................................... 57
Flow Diagram for the MessageDemo Macro .............................................................. 59
Appendix: VBA Message Box Constants........................................................................ 60
Notes and Further Information.................................................................................... 61
About the Author .................................................................................................. 61
© Martin Green www.fontstuff.com 2
VBA Message Boxes
Copyright............................................................................................................. 61
Limitation of Liability ............................................................................................. 61
This document describes the various different types of message box that can be created with
VBA and explains how to program them. It also describes the VBA input box which, in
addition to displaying a message, can receive typed input via its built-in textbox, and a
special variation of the input box which is available in Excel.
Much of the information here applies equally to all the Microsoft Office applications that can
be programmed with VBA.
It concludes with an exercise in Excel in which several different kinds of message box are
used, illustrating how message boxes and input boxes can be used to inform and interact
with the user.
Follow the instructions exactly. Read the instructions carefully and do exactly what they
say. Take care when typing. Remember that the computer takes all your instructions
literally.
Things you have to do are highlighted grey. I explain and illustrate the process as the
exercise proceeds so to distinguish my text from your practical instructions everything you
need to do has a grey background like this.
Instructions are sequentially numbered. So that you can keep track of where you are in
an exercise each step is numbered e.g. Step 1, Step 2 and so on.
"Click" means on the screen. If you have to "click" something it means with your mouse
on the screen, such as a button on a dialog box e.g. Click OK or Click the OK button. Unless
otherwise stated, mouse clicks are made with the primary (usually the left) mouse button. If
it is required to use the secondary (usually the right) mouse button you will be asked to
right-click.
"Press" means on the keyboard. If you have to "press" something it means a key on the
keyboard e.g. Press [Enter] or Press the Enter key.
When Key presses or keyboard shortcuts are required special key names are enclosed
in square brackets e.g. [Enter]. When combinations of key presses are required they are
written thus [Control]+[Enter]. This means hold down the Control key whilst pressing the
Enter key. Function keys are indicated thus: [F8] , [F11] etc.
Choosing menu items is usually indicated by Open the Tools menu and choose Macro then
Macros. Sometimes this is shortened to Go to... or Choose Tools > Macro > Macros.
If you don't understand an instruction don't panic! None of these exercises can harm your
Office programs or your computer. I recommend that, at least to begin with, you always
carry out the practice exercises in a new document or workbook. If things go wrong you can
simply stop the exercise, throw away the document or workbook, and start again.
These exercises have been thoroughly checked and tested. If you find an error in one of
them please let the author know about it. For contact details see: About the Author on
page 61.
Message Boxes
Every Windows user is familiar with the message box. It is used universally to communicate
with the user in many different circumstances. Message boxes can be used to provide
information to the user, or to obtain a response when a decision has to be made. They can
display a choice of different icons and various combinations of buttons.
It is made up of a number of component parts most of which can be modified with VBA:
Title: The title bar at the top of the box displays the Title text which can be specified by the
programmer. If no title is defined the message box displays the name of the program here.
Close Button: In the upper right corner is a Close Button which is enabled only if the
message box displays just an OK button, when clicking it is equivalent to clicking the OK
button; or if the combination of buttons includes a Cancel button, when clicking it is
equivalent to clicking the Cancel button. If any other combination of buttons is chosen the
close button is disabled.
Icon: A selection of different icons is available (see: Message Box Icons on page 6). The
message can be displayed without an accompanying icon if required.
Prompt: The message itself is called the Prompt in VBA. It can contain several lines and the
VBA programmer can determine where line breaks occur if they wish.
There is a limit to the length of the text in the title. This varies depending upon the mix of
characters (in a proportional font the characters are of different widths) and the Windows
display settings where fonts and point size can be specified. But since you are unlikely to
know the users' display settings it is advisable to keep the title text brief. The width of the
message box will increase to accommodate the title up to its maximum of approximately 50
characters. If the title text contains more than can be displayed it is truncated and an ellipsis
(...) placed at the end of the displayed text.
Icons convey an important message to the user and help reinforce your own message text.
There is no restriction on which icon is used with which button combination but it pays to use
them logically. Here are some suggested guidelines...
The Information icon (VBA constant: vbInformation) lets the user know that
the message is only providing information and requires no action on their part
other than an acknowledgement. You are most likely to use this in conjunction
with just an OK button.
The Question icon (VBA constant: vbQuestion) tells the user that they have to
make a decision. This would normally be used where there is an message in the
form of a question and a combination of buttons such as Yes and No.
As its name suggests the Critical icon (VBA constant: vbCritical) indicates a
high level of alarm. This one is usually reserved for when there is a serious
problem, such as a macro error, when the situation can not be recovered. It
suggests a message like: "We have a problem!"
Note that a message box can display only one icon at a time. If you want to display more
than one icon, or one different to those normally available, you should consider mimicking a
message box with a VBA UserForm (the use of VBA UserForms is covered in detail in another
title in this series: VBA UserForms).
When a message box is displayed one of the buttons is the default button. That button is
highlighted with a heavy external border and a dotted internal border. If the user presses the
Enter key on their keyboard the message box will behave as if the default button had been
clicked. If there is a Cancel button on the message box and the user presses the Escape
key on their keyboard the message box will behave as if the Cancel button had been clicked.
vbOKOnly
vbOKCancel
vbYesNo
vbYesNoCancel
vbRetryCancel
vbAbortRetryIgnore
vbYesNo + vbMsgBoxHelpButton
If a Help button is displayed it has no function unless the programmer specifies the name of
a Help file and a context number within the Help file so that appropriate help is displayed
(see: Using the Help Button on page 18).
When the requirement is simply to convey information to the user the MsgBox method is
used and it is necessary only to display the OK button. Its programming consists of a
specification of its design and its message.
When a message box is designed to take some input from the user the MsgBox function is
used. The message box will have more than one button, and its programming will also
include the interpreting and processing of the user's response (i.e. which button they
clicked).
When programming a message box, if the Visual Basic Editor's AutoQuickInfo feature is
enabled, help is displayed indicating what information is required (Fig. 4). The Message box
can accept up to 5 parameters. All except the Prompt are optional.
Fig. 4 The Visual Basic Editor displays AutoQuickInfo for a message box.
Parameter Description
Prompt The Prompt is the text of the message itself. It is supplied as a string
and should be enclosed in quotes ("). The message can be up to 1024
characters long. Although the text will automatically wrap within the
message box, you can control the flow of text by inserting commands
that force a new line (see: Multi-line Messages below).
Title The Title parameter (optional) is the text that appears in the title bar at
the top of the message box. It is supplied as a string and should be
enclosed in quotes ("). The amount of text possible is limited by the
width of the message box and depends upon your display settings. With
normal Windows settings about 50 characters can be displayed.
HelpFile If a Help button is displayed, this parameter can be used to specify the
path to the relevant Help file. The user can also access this help by
pressing the F1 function key whilst the message box is open (even if no
Help button is used). This parameter is used in combination with the
Context parameter.
Context The Context parameter gives the location of the help within the help file
specified in the HelpFile parameter. Both HelpFile and Context
parameters are optional but if used, both parameters must be supplied.
You can try this exercise in any Microsoft Office program that supports VBA programming.
Sub ShowMessage
Step 2: Place your cursor in the empty line between the Sub and End Sub lines and press
[Tab] to indent your code line then type:
MsgBox
followed by a [Space].
This prompts the Visual Basic Editor to display the AutoQuick Info help showing the various
parameters required:
The word Prompt is highlighted in bold indicating that the Visual Basic Editor is expecting
you to supply the message next so...
Then type a comma to display the list of choices, and scroll down to the item
vbInformation.
Step 4: Double-click the item vbInformation, then type a comma and enter the text of
the title in quotes as follows:
"Job Done"
Your code window should now look like this:
As with all VBA code you should not finish a line of code with a comma. Typing a comma
after the closing quote mark of the title would imply that you were going to supply another
parameter, and the Visual Basic Editor would display an error message if you then failed to
do so.
Step 5: Finally, with your cursor located anywhere within the macro code, press the [F5]
key to run the macro.
Sub ShowMessage()
MsgBox "The macro is complete", vbInformation, "Job Done"
End Sub
If you want to skip one or more parameters, accepting the defaults, just type another
comma to move to the next parameter. For example, if you did not want to show an icon
your code would look like this:
Sub ShowMessage()
MsgBox "The macro is complete", , "Job Done"
End Sub
Note that even though no button combination was specified, the default "OK" button was
displayed. This was indicated in the AutoQuickInfo help where the second parameter was
shown as: [Buttons As vbMsgBoxStyle = vbOKOnly]
Multi-line Messages
Unless it is instructed otherwise, a message box will display its message text as a single line.
The message box increases in width to accommodate the message text until its maximum
width is reached when the text wraps automatically on to a new line. The exact maximum
width of a message box depends on the current Windows Appearance settings, but the
following examples will give you some idea.
In the example below (Fig. 7) a very long piece of text was inserted into a message box. The
text was truncated when the limit was reached (1024 characters including spaces). The text
is displayed as a single block without any forced line breaks and (quite apart from the fact
that it is written in nonsense Latin!) would be quite difficult to read if this were a genuine
message.
When constructing a message it is important to think carefully about the user and to present
the message in a way that is easily read and understood. Most computer users will at some
time have been faced with a message that just didn't make sense!
Even a fairly short and simple message can often be made clearer by being broken into
separate lines. Placing several different pieces of information on one line makes them
difficult to separate visually (Fig. 8).
The same message rephrased and broken into several lines is much easier to read and
understand (Fig. 9).
The flow of message text can be controlled using special commands. This can be done in
several ways, my preference being to use the vbCrLf constant. The message is split into
sections, each enclosed in quotes, and the command inserted between the sections using the
ampersand (&) character. The following exercise demonstrates how this is done.
Sub MultiLineMessage
Step 2: Place your cursor in the empty line between the Sub and End Sub lines. Press
[Tab] to indent your code line and type:
A space followed by an underscore at the end of a line of VBA code is referred to as the
line continuation or line break character. It tells the code engine that the current code
statement continues on the next line. At this point your code should look like this:
Step 3: Press [Enter] to create a new line then press [Tab] to further indent the code
and type:
The ampersand character (&) concatenates (joins together) the various parts of the message
code, including the VBA constant vbCrLf which represents a combination of "carriage return"
and "line feed". Your code statement is instructing the message box to display: a piece of
text and a new line and another piece of text... and so on.
Step 5: Press [Enter] to create a new line and type a comma to move to the next
parameter. The AutoListMembers help will display a list of items. Scroll down the
list and double-click the item vbInformation.
"Job Done"
Your code should now look like this:
Step 7: Finally, with your cursor located anywhere within the macro code, press the [F5]
key to run the macro.
The macro created a multi-line message box with just an OK button (Fig. 10):
Sub MultiLineMessage()
MsgBox "The macro is complete" _
& vbCrLf & "Please remember to save the file." _
& vbCrLf & "Have a nice day!" _
, vbInformation, "Job Done"
End Sub
If you imagine typing your message directly on to the message box, using the "new line"
command is just like pressing [Return] or [Enter]. It can be repeated to create empty lines
in the message, as in this example:
Sub MultiLineMessage()
MsgBox "The macro is complete" _
& vbCrLf & "Please remember to save the file." _
& vbCrLf & vbCrLf & "Have a nice day!" _
, vbInformation, "Job Done"
End Sub
The resulting message box looks like this (Fig. 11):
As an alternative to the vbCrLf (carriage return+line feed) command you can use vbCr
(carriage return), vbLf (line feed), Chr(13) (carriage return), Chr(10) (line feed) or
Chr(13) & Chr(10) (carriage return+line feed) commands. All essentially do the same thing
although they may not work in the same way in all circumstances. Choose whichever you
prefer.
NOTE: Don't confuse the line breaks in the code with instructions to break lines in the
message. In these exercises I have used the line break character (a Space followed by an
Underscore) to break the code statement itself into separate lines to make it easy to read
in the Visual Basic Editor and on these pages. This has no bearing on the appearance of the
finished message box. The entire MsgBox code statement could be written in a single line
(omitting the line-break characters) and the result would have been just the same.
When MsgBox is used in this way in VBA it behaves as a function returning a value to the
procedure when the user clicks one of the buttons. There are seven different button
constants, each one having a numerical equivalent:
VbOK = 1
vbCancel = 2
vbAbort = 3
vbRetry = 4
vbIgnore = 5
vbYes = 6
vbNo = 7
It is this value that is returned to the procedure when the user makes their choice. In
context, each one can be referred to by their name or their integer value. I prefer to use the
name because I find it easier to understand when reading code.
The usual procedure is to declare a variable to hold the value. This variable can have an
Integer data type (since the numerical values of the constants are integers) or, from
Microsoft Office 2000 onwards, the special data type vbMsgBoxResult.
Having placed a value into the variable by displaying the message box, it can be evaluated
with an If Statement or a Case Statement.
Sub DeleteSheet
The next step is to declare a variable to receive the value of the button chosen by the user.
Now a value is assigned to the variable by displaying a message box. Note how, because
MsgBox is working here as a function its parameters are enclosed in brackets (strictly
speaking they should be called arguments now that they supply information to a function).
Step 4: Type a comma to move to the next parameter and prompt the list of options to
appear. Scroll down the list and double click the item vbQuestion.
Step 5: Type a plus sign (+) to prompt the list to appear again then find and double-click
the item vbYesNo.
A plus sign is used to "add together" the constants when you want to specify a button type
and an icon. If you try to specify two button types or two icons, something a message box
can not display, it reverts to the default setting and displays just an OK button and no icon.
Step 7: Press [Enter] to move into a new line and press [Backspace] to remove the
indent.
The code now has to evaluate the user's response which, in this case is very easy so a simple
If Statement will suffice. If the user clicked the No button then there is no more to do and
the macro can terminate...
Step 8: Type:
Any code which now follows will be executed only if the user clicked the Yes button.
Step 9: Type the following three lines of code to complete the procedure:
Application.DisplayAlerts = False
ActiveSheet.Delete
Application.DisplayAlerts = True
The finished code should look like this:
The code lines either side of the one that actually deletes the current sheet serve to suppress
then restore the warning message that Excel normally displays when a worksheet is deleted.
If you use this command to turn off alerts you must remember to include the command to
turn them on again, otherwise no more warnings will be displayed until you restart Excel!
Step 10: Check your code by opening the Visual Basic Editor's Debug menu and choosing
Compile VBAProject. If there are any errors in your code the compiler will point
them out now. Correct any errors it finds.
Step 11: Switch to Excel and, having made sure you are on a worksheet that it is safe to
delete, use the keyboard shortcut Alt+F8 to open the Macro dialog. Choose the
DeleteSheet macro and click the Run button to display the message box.
First of all click the No button and note that the message box disappears and the
sheet is not deleted. Then repeat the procedure and choose the Yes button and
note that the active worksheet is deleted.
The macro created a two-button Yes/No message box (Fig. 12) and a simple If Statement
handled the user's response.
Sub DeleteSheet()
Dim intResponse As Integer
intResponse = MsgBox("You are about to delete the current sheet." _
& vbCrLf & "Do you wish to continue?" _
, vbQuestion + vbYesNo, "Are you sure?")
If intResponse = vbNo Then Exit Sub
Application.DisplayAlerts = False
ActiveSheet.Delete
Application.DisplayAlerts = True
End Sub
The method used to evaluate the user's response depends upon the number of buttons. If
there are two buttons (such as Yes/No or OK/Cancel) it is safe to assume that if they
didn't click one they must have clicked the other. But if there are three buttons it a bit more
complicated. If the user didn't click the first button you still need to know whether they
clicked the second or the third.
The macro is intended for use in Microsoft Word and writes the current date into the active
document at the insertion point...
Sub EnterDate()
Dim strDate As String
Dim Response As VbMsgBoxResult
Response = MsgBox("Would you like the Long Date format?" _
, vbQuestion + vbYesNoCancel, "Writing Date")
Select Case Response
Case vbYes
strDate = FormatDateTime(Date, vbLongDate)
Case vbNo
strDate = FormatDateTime(Date, vbShortDate)
Case vbCancel
Exit Sub
End Select
Selection.TypeText strDate
End Sub
The macro starts with the declaration of two variables. The first one (strDate) is a string
variable which will hold the text to be inserted into the document. The second one
(Response) is declared here as a VbMsgBoxResult which identifies it specifically as one of
the message box button constants (NOTE: since this type was new in Office 2000, Office 97
users should declare this variable as an Integer instead).
Then a value is placed into the Response variable by displaying a Yes/No/Cancel message
box (Fig. 13).
The message box asks the user if they would like to use the Long Date format. They can
choose Yes (the macro will write a date like 27 September 2005), No (the macro will write a
date like 27/09/05 or 09/27/05 depending on your regional settings) or Cancel (the macro
will do nothing.
When the user clicks one of the buttons, the message box closes and passes a value to the
variable. The value is the numerical equivalent of the button constant: vbYes = 6, vbNo =
7, vbCancel = 2. As long as they are used in the correct context, you can write either the
constant name or its value into your code. It will understand what you mean. I prefer to use
constant names as they are easy to remember when writing and reading code (people who
use the numbers are just showing off!). You can find a complete list of VBA message box
constants in Appendix: VBA Message Box Constants on page 60.
Next comes a Case Statement which looks at the value of the Response variable and acts
accordingly. If the value is 6 (vbYes) it writes a long date into the strDate variable with the
help of the VBA FormatDateTime and Date functions. If the value is 7 (vbNo) it writes a
short date into the strDate variable. If the value is 2 (vbCancel) then the macro
terminates.
Finally (if the macro did not terminate because the user clicked Cancel) the date is written
into the document.
I normally prefer to use a Case Statement when there are more than two choices to evaluate
because I think Case Statements are easier to read, but an If Statement would work just as
well. To do the same job using an If Statement replace the lines from Select Case to End
Select in the previous code listing with the following:
ActiveCell.Value = strDate
A message box can display up to four buttons, and any one can be designated the default.
You can, however, offer a link to the built-in help. When programming the "Help" button you
need to supply two pieces of information: HelpFile (the name and location of the file that
contains the help), and Context (an ID number – like a bookmark – to identify the individual
help topic).
This information differs between versions of Microsoft Office. In Excel, for example, Excel 97
uses the old-style Windows help files (the main help file is named Xlmain8.hlp); Excel 2000,
2002 and 2003 use the newer HTML help files (named Xlmain9.chm, Xlmain10.chm and
Xlmain11.chm respectively). You should check the location of these files on your particular
installation.
To ascertain the Context ID of the appropriate bit of help is not so easy. Various authors have
compiled helpful lists (for example see: http://www.j-walk.com/ss/excel/tips/tip89.htm). In
Excel 2000/2002/2003 you can navigate to the desired help then right-click on the help page
and choose View Source. Look for a reference to "Tnum" followed by a 6-digit number
somewhere near the top of the source code (Fig. 15).
Fig. 15 The source code behind a help page includes the Tnum Help context number.
The message box code in the last example, modified to include a help button linked to
relevant help would look something like this:
NOTE: When the "Help" button is clicked the message box remains open. All other buttons
cause the message box to close when clicked.
If a message box is Application Modal it will appear on top of the host application window
but, if the user is working in a different application (i.e. if a different program window
currently has the focus) the message box will not interrupt them. Windows XP alerts the user
to the fact that another application needs their attention by highlighting its taskbar button
(Fig. 16).
Fig. 16 Windows XP alerts the user that another application needs their attention.
The user is also prevented from working in the host application until the message box has
been dismissed. All message boxes are Application Modal by default but you can specify it in
the code if you wish...
it will remain visible, on top of all open windows. Both kinds of message box prevent you
from working in the host program. (NOTE: I have described how System Modal is supposed
to work but in practice it does not always function as expected.)
It is important to remember that, even when the display of a message box is the last action
of a macro, the procedure is still running as long as the message box is open. When you are
testing your code, you will find that an open message box will prevent you from working in
the Visual Basic Editor.
The following code line has been broken using a "space & underscore" line continuation
command to fit conveniently into the code window:
But as it stands the code will be rejected by the Visual Basic Editor and an error message will
be displayed (Fig. 17).
The code has been rejected because the line continuation has occurred in the middle of a
string (a piece of text). When splitting a string you must provide each part with both opening
and closing quote marks and the various parts of the string must be concatenated (joined
together) using the ampersand character (&). The code should have been written like this:
Splitting strings like this has no effect on the arrangement of text in the message box (see:
Multi-line Messages on page 10). Note that I have left a space at the end of the first string,
before the closing quote mark. If I had not done that there would have been no space
between the last word of the first string and the first word of the next string when the
message box was displayed (Fig. 18).
To add text to data simply concatenate the items using the ampersand character (&),
remembering to include spaces where text and data join. This code statement uses the VBA
Format function to modify the displayed date and adds some text...
In the last two examples the included data was created within the message box statement
itself. It is just as easy to add information that is stored in a variable. The next example uses
a Case Statement to generate an appropriate greeting depending on the time of day...
If, like me, the last example bothers you because the first part of the message ("Good
afternoon.") is followed by a full-stop (a period) but the second part ("Today is Thursday")
lacks one, some people might say that you need to get out more but I say that you are good
programmer material! Little things like that show the attention to detail that makes the
difference between a professionally produced application and one that lacks care. Nobody
notices when things are OK but they will quickly spot things that don't look right, regardless
of how insignificant and unimportant they might seem to you. Here's the improved version...
MsgBox strGreeting & " Today is " & Format(Date, "dddd") & ".", _
vbInformation
Here's a better looking message (Fig. 22):
You have to pay particular attention to this when creating messages which contain items
which are themselves in quotes. For example, the following code statement will be rejected
by the Visual Basic Editor...
When the Visual Basic Editor comes across a quote mark it looks for the next matching quote
mark and assumes that whatever falls between them is a complete string. Here it can see
the string "The name " and the string " is not recognised." and does not know what to
make of the letters ACME between them (Fig. 23):
There are two solutions to the problem. One is to alternate double and single quotes, for
example:
MsgBox "The name " & Chr(34) & "ACME" & Chr(34) & " is not recognised."
This produces a message containing the required arrangement of quotes (Fig. 24):
When this code statement is run in Microsoft Excel the resulting message box displays the
square root of the number in the active cell in the message, and the text "Cell: " followed by
the selected cell's address in the message box title. (NOTE: I have used the VBA Replace
function to remove the dollar signs from the address by replacing them with nothing. The
Address property always returns the address in the format $A$1 whereas A1 is easier for
the user to read.)
The following code statement displays a message box in Microsoft Word in which the
message shows the word count and the title shows the document's name.
Similarly, should you decide to change the name of your application, or sell it to a different
company, all that you need to do is change the value of the constant. You won't have to find
and change each message box.
To save you having to remember to enter that bit of information in exactly the same way you
can store it in a VBA constant. A constant has its value "hard-coded" (i.e. written in by the
programmer) when it is declared. If it is declared as a public constant all the macros in the
same project will be able to refer to it and read its value.
You can declare a constant in any regular code module (not an object module such as that
attached to a worksheet or workbook in Excel or the document module in Word). Place the
code in the declaration area at the top of the module outside of and before any macros.
You can now call on the value of the constant in any of your procedures. Just substitute the
name of the constant for the text you would otherwise have written. Here's an example of a
message box that makes use of the constant to display the company name in the title bar of
the message box:
MsgBox "This macro will carry out the following tasks:" & _
vbCrLf & "1. Archive the old file" & _
vbCrLf & "2. Create a new file" & _
vbCrLf & "3. Name and save the new file" & _
vbCrLf & "4. Print a copy of the new file" & _
vbCrLf & "Click OK to continue." _
, vbInformation, "Acme Logisitics Corporation"
Similarly there is no automatic indent facility so to indent the list add some spaces to the
start of each line of the message text (Fig. 28 right):
MsgBox "This macro will carry out the following tasks:" & _
vbCrLf & " 1. Archive the old file" & _
vbCrLf & " 2. Create a new file" & _
vbCrLf & " 3. Name and save the new file" & _
vbCrLf & " 4. Print a copy of the new file" & _
vbCrLf & "Click OK to continue." _
, vbInformation, "Acme Logisitics Corporation"
Fig. 28 A manually numbered list without (left) and with (right) indents.
When it comes to adding bullets to a list you will have to make your choice from the various
characters available to you in the standard message box font (normally Tahoma in Windows
XP as shown in these screenshots).
Several different characters are suitable for use as bullets. In this example the right single
angled bracket is used and, since it is one of the characters represented on the standard
keyboard, it can be typed directly into the code (Fig. 29):
MsgBox "This macro will carry out the following tasks:" & _
vbCrLf & "> Archive the old file" & _
vbCrLf & "> Create a new file" & _
vbCrLf & "> Name and save the new file" & _
vbCrLf & "> Print a copy of the new file" & _
vbCrLf & "Click OK to continue." _
, vbInformation, "Acme Logisitics Corporation"
You could also use the hash mark (#) or a simple dash (-). But the standard character set
includes more characters than shown on the standard keyboard including some that make
suitable bullets. These additional characters can be added by specifying their ASCII character
codes with the help of the VBA Chr() function. Suitable characters include the center dot
(character 149: •), the currency symbol (character 164: ¤) and the double right angled
bracket (character 187: ») (Fig. 30).
MsgBox "This macro will carry out the following tasks:" & _
vbCrLf & Chr(187) & " Archive the old file" & _
vbCrLf & Chr(187) & " Create a new file" & _
vbCrLf & Chr(187) & " Name and save the new file" & _
vbCrLf & Chr(187) & " Print a copy of the new file" & _
vbCrLf & "Click OK to continue." _
, vbInformation, "Acme Logisitics Corporation"
You can't add custom captions to message box buttons (Fig. 32)...
You can't add interactive controls such as combo boxes (Fig. 33)...
These are just a few of the things you can't do with message boxes. But don't despair! All
the examples shown here are fully functioning "real" objects that I created using the Visual
Basic Editor but they were not made using the VBA MsgBox. They were created as VBA
UserForms, custom forms designed and coded within the Visual Basic Editor.
You can read about how to create and use them in the companion to this volume:
VBA UserForms available from the author's web site at http://www.fontstuff.com.
Input Boxes
The VBA input box is similar to the message box in that it displays a message to the user,
but it has the added facility of a text box into which the user can make an entry which is
returned to the program when the input box closes.
There are two types of input box. The VBA InputBox function is available to all applications
which use VBA and returns the user's input as a string (text) whatever it is. It is entirely up
to the programmer to handle the input. Microsoft Excel has its own InputBox method which
has an additional feature allowing the programmer to specify the kind of input the input box
will accept. Both types look and function in a similar way so I will describe the VBA input box
function first then explain how to use the additional features of the Excel input box method.
Title: The title bar at the top of the box displays the Title text which can be specified by the
programmer. If no title is defined the message box displays the name of the program here.
Unlike the VBA message box, which will increase in width up to its maximum to fit the title
text, the width of the VBA input box is fixed. It will accommodate up to approximately 50
characters. If the specified title exceed the limit it is truncated and the missing text replaced
with an ellipsis (...).
Close Button: In the upper right corner is a Close Button which is always enabled. Clicking
the Close Button has the same effect as clicking the Cancel button or pressing the [Escape]
key on the keyboard – the input box closes and returns a zero length string ("").
Prompt: The message itself is called the Prompt in VBA. It can contain several lines and the
VBA programmer can determine where line breaks occur if required. The maximum length of
the prompt is approximately 1024 characters. As the amount of text increases the input box
will increase in height to accommodate it but its width remains constant (Fig. 35).
Buttons: The same combination of buttons is always displayed (OK and Cancel). Clicking
the OK button returns the value of the text box as a string. Clicking the Cancel button
returns a zero length string (""). A Help button can also be added and appears automatically
when a help file is specified in the code. Unlike the VBA message box the input box can not
display other combinations of buttons.
Text Box: Any entry the user makes into the text box is returned as a text string, although
the programming of the input box allows this input to be handled in different ways. A default
entry can be specified if required.
Fig. 35 The input box displaying its maximum amount of prompt text.
When programming an input box, if the Visual Basic Editor's AutoQuickInfo feature is
enabled, help is displayed indicating what information is required (Fig. 36). The input box
can accept up to 7 parameters. All except Prompt are optional.
Fig. 36 The Visual Basic Editor displays AutoQuickInfo for an input box.
Parameter Description
Prompt The Prompt is the text of the message and should be enclosed in quotes
("). The message can be up to 1024 characters long. Although the text
will automatically wrap within the input box, you can control the flow of
text by inserting commands that force a new line (see: Multi-line
Messages in the section on message boxes on page 10).
Title The Title parameter (optional) is the text that appears in the title bar at
the top of the input box and should be enclosed in quotes ("). The
amount of text possible is limited by the width of the input box and
depends upon your display settings. With normal Windows settings
about 50 characters can be displayed.
Default This optional parameter allows you to specify a default entry for the
input box. It must be supplied as a string (i.e. text enclosed in quotes)
and appears automatically in the text box when the input box opens. If
you do not supply a default entry the text box is displayed empty.
XPos Use the XPos parameter to optionally specify the horizontal distance of
the left edge of the input box from the left edge of the screen. If it is
omitted, the input box is horizontally centered on the screen.
Dimensions are specified in "twips".
YPos Use the YPos parameter to optionally specify the vertical distance of the
upper edge of the input box from the top of the screen. If it is omitted,
the input box is vertically positioned approximately one-third of the way
down the screen. Dimensions are specified in "twips".
HelpFile The HelpFile parameter can be used to specify the path to the relevant
Help file. The user can also access this help by pressing the F1 function
key whilst the input box is open or by clicking the Help button, which is
automatically displayed if the HelpFile parameter is supplied. This
parameter is used in combination with the Context parameter.
Context The Context parameter gives the location of the help within the help file
specified in the previous parameter. Both Help File and Context
parameters are optional but if used, both parameters must be supplied.
If the value returned by the input box is going to be used immediately it might not be
necessary to store it in a variable. The code could pass the value direct to it's destination.
For example, a value could be passed directly into a cell on an Excel worksheet:
The following statement passes the user's response directly to a bookmark in a Microsoft
Word document (Fig. 38):
ActiveDocument.Bookmarks("Recipient").Range.Text = _
InputBox("Enter the recipient's name.")
Fig. 38 Passing a value from an input box directly to a bookmark in a Word document.
The value returned from an input box can be passed directly to a calculation or included as
an argument in another function. This statement asks the user to supply two numbers which
it then multiplies and displays the result in a message box:
The InputBox function always returns a string. Since any typed input can be treated as a
string this is not a problem. Dates, numbers and text are all just strings of characters. What
your code subsequently does with that input, and what can go wrong, depends upon whether
or not you get what you were expecting.
If you want to error-check the user's input it makes sense to pass it to a variable. You can
then carry out whatever checks are necessary before proceeding. There are two ways to do
this. You can use a string variable, or a variable of the data type matching what you are
expecting to receive.
© Martin Green www.fontstuff.com 30
VBA Message Boxes
Whatever the user types is returned as a string so there's no problem placing it into a string
variable. You can then test the value of the variable to see what it is.
Suppose you ask the user for a date. You can use the VBA IsDate() function to check the
result...
But it does its best to work "intelligently" so even if an incomplete date is supplied you might
get an acceptable result. If just month and day are supplied the system assumes you want
the current year (Fig. 40):
We know that each date can be represented by a number (its DateSerial) but since, in this
case, the number is arriving as a string and the system can't interpret it as a date (Fig. 41):
Numbers and slashes will usually be interpreted as dates even when a full date is not
supplied (Fig. 42):
The system juggles the input to see if a valid date can be created, so you might not get the
result you expected (Fig. 43):
Fig. 43 The system tries hard to create a date from the input.
Don't let this deter you from using an input box to collect information from the user! You just
need to use the right approach. To begin with, you might suggest a date format to the user
as part of the input box prompt (Fig. 44). Then check their input before making further use
of it.
An alternative method is to use a variable of the data type that matches the type of input
you want from the user. You will find that the results might differ by this method because
the input is checked for data type by the variable itself. A date variable will accept only a
value that can be interpreted as a date, so unlike the example above (Fig. 41), any valid
date serial will be accepted (Fig. 45):
When, as in this example, a date variable is used you need to approach the checking of the
input in a different way. If the user supplied an input that is not accepted by the variable
then an error results (error number 13 – "Type Mismatch").
The following example uses the On Error Resume Next statement to allow the code to
proceed after an error occurs. An If Statement then checks to see if Error #13 has occurred
and proceeds accordingly. The On Error GoTo 0 statement clears any error that might have
occurred and reverts the code to the default error handler...
My preference is to avoid errors so I usually pass the input to a string variable and do
whatever is necessary to check its validity. Sometimes this requires a bit of ingenuity since
there are only a few ready-made functions for checking data: IsDate() (is it a date?),
IsNumeric() (is it a number?) and IsLogical() (is it True or False?).
On the other hand, variables can be declared in a variety of different data types: Date,
Integer, Long, Double etc. each of which will only accept values which strictly conform to
their type, so this method might involve less work testing the input.
This example uses the VBA IsNumeric() function to test if the user has input a number. If it
passes the test (it isn't necessary to use = True in your code as this is assumed with logical
functions) then the Exit Do statement causes the procedure to jump out of the Do...Loop
loop and proceed (Fig. 46). If it doesn't pass the test the user is asked to try again (Fig. 47)
the loop repeats until a satisfactory input is received.
A zero length string is a text object containing no text. It is represented in VBA by a pair of
quote marks with nothing between them ("").
You will probably want to take a different course of action, such as aborting the procedure, if
the user decides they don't want to supply the requested information. A simple If Statement
will do the job. Here's an example (Fig. 48):
An alternative would be to use the If Statement to measure the length of the string held in
the variable using the VBA Len() function. If the length is zero then you know that the user
has cancelled. The first line of the If Statement would read:
If Len(strUserName) = 0 Then
Bear in mind that the user might have cancelled by mistake. Making them start over might
be a little harsh! With a little extra code you can give them the opportunity to try again.
Contrast the following code with that suggested earlier (see: Let the User Try Again on page
33) where the user is forced to keep trying until they get it right. This example asks them if
they want another attempt and allows them cancel the procedure if they don't.
NOTE: I have used a simple example here. If you were really asking someone to log in you
would need to check that their username was acceptable by checking it against a list or
seeing if it conformed to a certain pattern.
I often take this opportunity to suggest a filename when using VBA to save a file. Here's an
example which creates a filename which is time-stamped by adding the current date and
time (created with the VBA Now function) and formatted using two digits for each unit
(year, month, day, hour, minute and second) created with the help of the VBA Format()
function.
When an input box containing a default value is displayed the entry is already selected (Fig.
49) so that, if they want to change it, the user just has to start typing...
The last line of the code displays a confirmation message (Fig. 50) to let the user know that
the file has been saved successfully:
NOTE: You might think that time-stamping to the second is excessive but I have a good
reason for doing it. If the time-stamp were accurate only to the nearest minute for example,
and the user ran the macro a second time, you would have to deal with the problem of two
files with the same filename. Even if you wanted the second to overwrite the first you would
have to include code to check for a conflict and deal with it accordingly.
In Excel it is more likely that the user's input will need to be validated so the InputBox
method's built-in data type validation can prove very useful. (NOTE: The VBA InputBox
function is still available to you in Excel so, if you don't require the additional features the
InputBox method offers you can still use the VBA one.)
Another major difference between the VBA InputBox function and the Excel InputBox
method is that whereas the former is application modal (i.e. the user can not work anywhere
else in the host program when it is open) the latter is not. In fact, when using the Excel
InputBox method you are probably going to ask the user to click on a particular cell or
select a range of cells for the appropriate values to be read into the input box. This feature
can be very useful when gathering information from the user since, if you know that the
value you require from them is displayed on the worksheet, you have the option of asking
them to click on the cell in which it is displayed to retrieve it and avoid the possibility of
typing errors.
When programming this type of input box it is important to insert the keyword "Application"
into the input box statement to make it clear which sort of input box you want. When you do
so you will see that the Visual Basic Editor's AutoQuickInfo help displays an additional
parameter called Type (Fig. 51).
The Type parameter is expressed as a number. There are seven to choose from:
0 A formula
1 A number
2 Text (a string)
64 An array of values
This simple statement asks the user for a number which it places into a variable called
Response.
The input box that Excel displays looks a little different from the VBA input box. It is a
slightly different shape and the buttons are below the text box instead of above it. As the
screenshot shows (Fig. 52) the title bar displays the word Input if no title is specified in the
code. It also displays a help button (actually a What's This button) on the title bar which
functions only if a help file and context are specified in the code (see: Using the Help Button
on page 18).
Fig. 52 A typical input box displayed using the Excel InputBox method.
NOTE: An alternative way to write this sort of statement, and avoid having to type so many
commas for all the skipped parameters, is to use Named Parameters (alternatively Named
Arguments). When permitted, this technique of code writing involves stating the name of the
parameter or argument followed by a colon and an equals sign (:=) and the value itself. Only
the parameters used need be specified although they still must be separated with commas.
It is also customary, to make the code easy to read, to place each on a separate line. Here's
an example:
My recommendation is that you always declare a data type for your variables. If you don't
know what that data type will be, or if several different ones are acceptable, you can declare
the variable as a Variant. If you declare a data type for your variable you can add an
additional layer of validation to your InputBox statement, but make sure that the data type
of your variable does not conflict with the data type you specified for the input box.
Suppose you are asking your user for a number, and you are expecting a small whole
number. You could, for example, declare your variable as a Byte. Using a Type 1 input box
will ensure that the user enters a numerical value (see: If the User Enters the Wrong Data
Type below). If the user enters a number greater than 255 an error will occur (Error #6 –
Overflow) when the input box tries to return the value to the variable. You can trap that
error and deal with it as you wish.
If the input box rejects the user's input, and displays one of the messages shown above, the
user is returned to the input box when they acknowledge the message. Your code does not
have to take account of this as the input box does not attempt to return a value until it has
received something acceptable, or until the user cancels (see: If the User Cancels the Input
Box below).
If the user's input is accepted by the input box a second check is performed when the input
box passes the value to the variable. Your code should include a procedure to deal with this.
You can avoid this second check causing problems by simply declaring your variable as a
Variant which accepts all data types.
The process works in a similar way to entering a formula directly into a cell. If the user is
constructing a formula in the text box they must start by entering an equals sign (just as if
they were typing in a cell). If the equals sign is omitted their typing is simply returned as a
string. In combination with their typing they can click on a cell to select it (they are
permitted to move to other worksheets or workbooks), or click and drag to select a range of
cells. The address of their selection is entered into the formula in the text box (Fig. 58).
When the user clicks the OK button the input box checks that an acceptable formula has
been entered and displays a warning message if any errors are found (Fig. 53) but unlike
Excel it does not automatically correct minor errors such as a missing closing parenthesis (as
shown in the unfinished example in Fig. 58).
Formulas involving cell addresses are returned in R1C1 format so when, as in this example,
the user enters the formula =SUM(A1:A5) the formula returned is =SUM(R1C1:R5C1). Both
formulas will produce the same result but if you prefer to see the formula in A1 format you
can convert it with the VBA ConvertFormula function. The following code displays both
formula styles in a message box (Fig. 59)...
A more practical use of this feature is to write the formula into a cell or range of cells. If the
formula to be entered was likely to be the same each time, you could use the input box's
Default parameter to assist the user by writing some of it for them:
The user can type directly into the input box's text box or click on a cell which contains a
numerical value. In the latter case, the input box displays the cell's address but returns its
numerical value (Fig. 60). If the cell contains a non-numerical value (such as some text)
then the input will be rejected just as if the user had typed the text directly into the input
box.
Fig. 60 When a cell is selected the Type 1 input box returns its numerical value.
If a date is entered into a Type 1 input box, or if the user selects a cell containing a date, the
date serial (a numerical representation of the date) is returned (Fig. 61). This value can be
handled by one of the many VBA date/time functions and converted back to a conventional
date format with the Format or FormatDateTime functions as illustrated in the following
example:
Fig. 62 A Type 2 input box returns the text value of a selected cell.
Zero FALSE
A date FALSE
The same applies to entries typed directly into the input box's text box with the exception
that, unlike an empty cell which is interpreted as false, an empty text box is not accepted as
a valid entry.
It is much more reliable, to include in your code a message asking the user to specify a
range of cells. This is where the Excel input box has a considerable advantage over the VBA
input box. With a VBA input box the user would have to type, accurately and in the correct
format, an address for the cell or range. But with the Excel input box they can simply use
their mouse to select the cells. They can see clearly which cells they have selected and,
especially with complex selections, there is no chance that an incorrect reference will be
returned.
When using a Type 8 input box you should declare the variable that is to receive the cell
reference as a Range and, because this is an object variable you must use the keyword Set
when applying a value to it. For example:
Fig. 63 A Type 8 input box can receive simple or complex cell references.
If the user clicks the OK button without having selected any cells, or having made an invalid
entry (such as a piece of text, a number or a bad cell reference) the input box's own
validation takes over and a message is displayed (Fig. 57) after which the user is returned to
the input box to try again.
If, however, the user cancels (by clicking the Cancel button or pressing they [Escape] key)
then the input box returns the value False which will cause the code to crash since the code
is attempting to place it into a Range variable. For this reason you must include some error
handling to deal with this possibility. The error that occurs if the user cancels is Error 424.
Here's an example of how to deal with it:
Once you have the range specified by the user it can be treated like any range in VBA
(remember that you have the Range object not just its Address property). For example, you
can manipulate the data within the cells by creating a loop that visits each cell in turn – this
example increases the values by 10%:
ChosenRange.Name = "TestData"
You can read and make use of the properties of the range (Fig. 64):
When using this type of input box it is worth considering whether the user might have
already selected the cells they want to process. You could save them the effort of selecting
the cells again by specifying the address of the current selection as the default value of the
input box:
A Type 16 input box accepts error values, those messages you see in a cell when something
has gone wrong. Excel displays 7 different error values, each corresponding to a particular
error number, as listed in the table below:
2000 #NULL! Occurs when you specify an intersection of two areas that do not
intersect. The intersection operator is a space between references.
2015 #VALUE! Occurs when the wrong type of argument or operand is used.
2029 #NAME? Occurs when Microsoft Excel doesn't recognize text in a formula.
To retrieve the error value the user can either click on the cell in which it is displayed or type
the message directly into the input box's text box. The input box code is set up in the usual
way, passing the error value to a Variant type variable.
The best (only?) way to deal with the value passed to the variable is to convert it to a
readable error number using the VBA CInt() function (which converts the error value to an
integer).
The following code tells the user why they are getting an error. The user should click on a
cell that is displaying an error code. If they prefer they can type the error code directly into
the input box's text box.
Case 2029
MsgBox "This error means that the formula contains text " & _
"that Excel doesn't recognise." _
, vbInformation, "#Name? Error"
Case 2036
MsgBox "This error means that the formula contains " & _
"invalid numeric values." _
, vbInformation, "#NUM! Error"
Case 2042
MsgBox "This error means that a value specified in " & _
"the formula is not available." _
, vbInformation, "#N/A Error"
Case Else
MsgBox "Excel does not recognise this an error code." _
, vbInformation, "Not recognised"
End Select
The code uses a Case Statement to display an appropriate message for the integer value of
the error code it finds in the cell. If the user cancels, the input box returns False which has
an integer value of zero. If this happens the code exits without displaying a message.
You can test the code by creating a faulty formula which produces an error code or (easier!)
type the code directly into a cell.
Unfortunately, if the user clicks on an empty cell or a types something other than an error
value into the input box's text box, the input box interprets this as Error 2015. I haven't
managed to find a way of avoiding this!
An array variable is a variable that can hold more than one value. If you think of a variable
as a box, into which a piece of data can be placed, then an array variable could be likened to
an egg-box, divided into sections so that it can hold several pieces of data, each in its own
compartment.
When you present the user with a Type 64 input box they select a block of cells on their
worksheet and click the input box's OK button. Excel reads the data from the selected cells
into an array variable, creating (to continue the analogy) a "virtual spreadsheet" whose
arrangement of data matches that of the selected cells. This data is held in the computer's
memory ready for you to read it from the array variable and do whatever you want with it.
When working with array variables in VBA it is customary to either specify the number of
elements and dimensions when declaring the variable, or to allow the variable to create as
many as it needs when data is placed into it, and then figure out the resulting number of
elements and dimensions afterwards.
When you are using a Type 64 input box you don't know how many cells, rows or columns
the user is going to select so you have to use the latter approach. Programming a Type 64
input box starts something like this:
NOTE: The pair of parentheses () after the variable name indicate that this variable is an
array. When dimensioning an array (specifying its size) that information is entered between
these parentheses.
The array variable for a Type 64 input box must be declared as a variant, even if you know
what type the data will be. If you try to declare it as a specific data type, such as String or
Double, the code will fail.
When reading data from the array variable you need to specify the item's location in the
array. In a one-dimensional array it is necessary only to specify the number of the element,
for example: arrData(1) specifies element 1, arrData(25) specifies element 25 etc. For a
multi-dimensional array it is necessary also to specify which dimension you are interested in,
for example: arrData(2,3) specifies the second element in the third dimension, arrData(32,6)
specifies the thirty-second element in the sixth dimension.
If you want to retrieve all the data from an array variable, or look through the variable for a
specific piece of data, the best method is to use a code loop.
When numbering the elements and dimensions of the array variable, a Type 64 input box
starts counting from 1 (it's important to remember this as in other circumstances the default
in VBA is to start counting from zero).
Since you probably have no idea in advance how many cells the user will select, or the shape
of the selection, you must assume that they might select more than one cell, and more than
one column and row. You can use the VBA UBound() function to determine the number of
elements in the array but there is no such function to tell you the number of dimensions. To
work around this handicap, my code reads the dimensions one at a time. If it tries to read
the data from a dimension that does not exist an error occurs and this tells me that I have
read all the existing dimensions.
The following code examples use two integer variables (x and y) to act as counters for the
elements and dimensions. They loop through the elements and dimensions of the array and
use the Debug.Print statement to "print" the value found in each element in the Visual
Basic Editor's Immediate Window (find it on the View menu or use [Control]+G to display
it). In practice you will probably want to substitute this statement with something else to
examine or manipulate the data you find.
There are four rows of data so the UBound() function returns the value 4 being the number
of elements in the array; and there are three columns of data so the array has 3 dimensions.
Debug.Print arrData(x, y)
If Err Then Exit Do
Next x
y = y + 1
Loop
On Error GoTo 0
This code reads the data from the array to the Immediate Window thus (Fig. 66):
This code uses a loop within a loop. To begin with the counter y (representing the dimension
number) is set to 1. The outer (Do...Loop) loop has no specified limit and will continue until
it is told to stop when an error occurs (by the statement If Err Then Exit Do). The inner
(For...Next) loop cycles four times (1 To 4 as specified by the value returned by the
UBound() function) and returns the data from elements 1,2,3 and 4 of dimension 1. When
the inner loop finishes the value of y is increased to 2 (to represent the second dimension)
and the outer loop cycles so that the inner loop runs again. This time it returns the data from
elements 1,2,3 and 4 of dimension 2. This continues until the value of y has reached 4 and
the inner loop tries to read the data from element 1 of dimension 4. Since the user selected
a block of cells three columns by four rows, there are only three dimensions in our array, so
this causes an error. The earlier On Error Resume Next statement allows the code to
continue after the error but the If Err Then Exit Do statement spots that there has been an
error and terminates the outer loop (also terminating the inner loop) and the reading of the
data from the array is complete.
The next code example returns the same data but this time by row:
Again the code has a loop within a loop but this time the outer loop represents the elements
and the inner one the dimensions. The outer (For...Next) loop will run four times (1 To 4)
as determined by the value returned by the UBound() function. To start with it will look at
the data in element 1. The inner (Do...Loop) loop returns the data from element 1 of
dimension 1, then dimension 2, and so on until it tries to read data in a dimension that
doesn't exist. At this point an error occurs. If that happens (If Err Then...) the dimension
counter is reset to 1, the error is "cleared" to take the code out of error mode (Err.Clear)
and the inner loop terminated (Exit Do). Returning to the outer loop, the procedure now
looks at element 2 of each dimension, then element 3 of each dimension and so on,
terminating the inner loop each time it runs out of dimensions, until the outer loop has
cycled the specified number of times.
Although this exercise uses Excel, the techniques it uses can be applied equally to any Office
program.
The exercise starts by adding data to an empty workbook. Then a basic macro is written, and
gradually improved by adding user interaction.
Step 4: Open the Visual Basic Editor (Keys: Alt+F11). Locate and select the current
workbook in the Project Explorer window and choose Insert > Module. In the
new module's code window type:
Sub MessageDemo
Dim i As Integer
Dim x As Integer
Step 6: Add the following lines to set the value of both variables to zero:
i = 0
x = 0
Step 7: Add the line:
Range("A1").Select
This starts the macro by making sure that the correct cell (A1) is selected. Cell A1 is now the
Active Cell.
Step 8: Now type the loop code that does the main work of the macro:
Do
If ActiveCell.Offset(i, 0).Value > 900 Then
ActiveCell.Offset(i, 0).Copy _
Destination:=ActiveCell.Offset(x, 1)
x = x + 1
End If
i = i + 1
Loop Until IsEmpty(ActiveCell.Offset(i, 0))
This procedure uses a Do...Loop Until loop to repeat the macro code until it finds an empty
cell in column A. The data in column A contains no gaps so this method will loop through all
the data.
The If Statement checks to see if a cell contains a value greater than 900. The cell that gets
checked depends upon the value of the variable i. This is achieved by defining the cell's
address location as ActiveCell.Offset(i, 0). The value if i is going to change each time the
loop repeats. It starts with a value of zero, so the first cell to get checked is
ActiveCell.Offset(0, 0) which is cell A1 itself (no offsets). The next cell is
ActiveCell.Offset(1, 0) which is cell A2, and so on. Later in the loop the line i = i + 1
increments the value of the variable by one.
If the If Statement finds that the cell contains a suitable number, it copies the value to
another cell using a similar method to decide its address. This uses the value of the variable
x. The value of x is going to change each time a number is copied. This is done with the line
x = x + 1. Note that x is inside the If Statement so its value is incremented only when a
number is copied, unlike i which is incremented ever time the loop cycles. The value of x
starts at zero, so the first cell to receive a number is ActiveCell.Offset(0, 1) which is cell
B1. The next cell is ActiveCell.Offset(0, 2) which is cell B2, and so on.
It is good practice to add confirmation messages to macros when it is not always obvious to
the user that the macro has finished.
Sub MessageDemo()
Dim i As Integer
Dim x As Integer
i = 0
x = 0
Range("A1").Select
Do
If ActiveCell.Offset(i, 0).Value > 900 Then
ActiveCell.Offset(i, 0).Copy _
Destination:=ActiveCell.Offset(x, 1)
x = x + 1
End If
i = i + 1
Loop Until IsEmpty(ActiveCell.Offset(i, 0))
MsgBox "The values have been copied to column B" _
, vbInformation, "Macro Complete"
End Sub
Step 10: First let the Visual Basic Editor carry out a check of the code by choosing Debug
> Compile VBAProject. Then click the Save button on the Visual Basic Editor
toolbar (or choose File > Save) to save your work.
Compiling causes the code compiler to perform a "dry run" of the macro. Whilst not
completely infallible, this tool helps to locate any undeclared variables, spelling errors or
other typos before running the macro for real.
Step 11: Switch to Excel and make sure that you are on the worksheet containing the
column of numbers. Press Alt+F8 (or go to Tools > Macro > Macros) to open
the Macros dialog and select MessageDemo. Click Run.
When the macro finishes click the OK button on the confirmation message box to
close the box and terminate the macro.
Step 12: Clear the contents of column B, ready for the next test, but leave column A intact.
You will code two message boxes. One will ask the user if they want to time the macro, the
other will display the elapsed time.
Step 13: Add the following lines after the existing variable declarations at the start of the
macro:
The first line uses a Yes/No message box to put a value into the Response variable. The
second line makes a not of the time by placing the Timer value in the StartTime variable.
Step 15: Move to the end of the loop, to the line for the confirmation message box
(MsgBox "The values have been copied... ) and type these additional lines so
the result looks like this:
This code uses an If Statement to check the users response to the earlier message box
asking whether they wanted to time the macro. The user's answer was stored in the
Response variable. If the user answered "No" they are shown the confirmation message and
the macro is terminated with the line Exit Sub. If the user answered "Yes" the macro
continues without displaying the confirmation message.
Step 16: Add this final line to the end of the macro to display a different confirmation
message, showing how long the macro took:
Sub MessageDemo()
Dim i As Integer
Dim x As Integer
Dim Response As VbMsgBoxResult
Dim StartTime As Double
i = 0
x = 0
Range("A1").Select
Response = MsgBox("Would you like to time this operation?" _
, vbQuestion + vbYesNo)
StartTime = Timer
Do
If ActiveCell.Offset(i, 0).Value > 900 Then
ActiveCell.Offset(i, 0).Copy _
Destination:=ActiveCell.Offset(x, 1)
x = x + 1
End If
i = i + 1
Loop Until IsEmpty(ActiveCell.Offset(i, 0))
If Response = vbNo Then
MsgBox "The values have been copied to column B" _
, vbInformation, "Macro Complete"
Exit Sub
End If
MsgBox "The procedure took " & Timer - StartTime & _
" seconds.", vbInformation, "Macro Complete"
End Sub
Step 17: Compile the code, save your changes then test run the macro as before.
This time you are asked a question at the start and shown a confirmation message at the
end. The confirmation message you see depends upon your answer to the question.
Step 18: Change the last line of the macro (the confirmation message) as follows:
There are several changes here. The message box is being used as a function to place a
value into the Response variable. You can reuse a variable as many times as you want, but
take care to be aware of which value it is holding at any time. When MsgBox is used as a
function (i.e. when it follows an equals sign) its parameters must be enclosed in brackets.
The icon has been changed to vbQuestion and the box will display both "Yes" and "No"
buttons, and a question has been added to the prompt.
Step 19: After the above lines, type the following If Statement which examines the
response to the question about viewing statistics:
This is an If Statement at its simplest with only one condition and a simple command that
can be written in a single line. If the user answered "No" then the macro finishes, otherwise
it continues.
Step 20: Finally, add code for a message box to display the macro statistics which are
contained in the variables i and x:
Sub MessageDemo()
Dim i As Integer
Dim x As Integer
Dim Response As VbMsgBoxResult
Dim StartTime As Double
i = 0
x = 0
Range("A1").Select
Response = MsgBox("Would you like to time this operation?" _
, vbQuestion + vbYesNo)
StartTime = Timer
Do
If ActiveCell.Offset(i, 0).Value > 900 Then
ActiveCell.Offset(i, 0).Copy _
Destination:=ActiveCell.Offset(x, 1)
x = x + 1
End If
i = i + 1
Loop Until IsEmpty(ActiveCell.Offset(i, 0))
If Response = vbNo Then
MsgBox "The values have been copied to column B" _
, vbInformation, "Macro Complete"
Exit Sub
End If
Response = MsgBox("The procedure took " & Timer - StartTime _
& " seconds." & vbCrLf _
& "Would you like to see the statistics?" _
, vbQuestion + vbYesNo, "Macro complete")
If Response = vbNo Then Exit Sub
MsgBox "The macro processed " & i & " rows." _
& vbCrLf & x & " values were found." _
, vbInformation, "Statistics"
End Sub
Step 21: Compile the code, save your changes then test run the macro as before.
If you answer "Yes" to the question about timing the macro at the start, you are shown the
time taken when the macro concludes but this time the confirmation message also asks you
if you want to see statistics. If you answer "Yes" again you will see a message showing the
number of cells checked and values copied.
the user prefers not to choose a number the computer will choose a number at random and
the user will be informed of its choice.
This procedure needs another variable to hold the user's choice of number (or the
computer's choice)...
Step 22: Add the following variable declaration to the list at the beginning of the macro:
In the next step you will enter the code to ask the user if they want to specify a minimum
number. Their choice will be placed in the existing Response variable. It is safe to do this
because the macro will have read the value before the variable is needed again.
Step 23: Type this code near the start of the macro, above the line Range("A1").Select :
• To take control of the situation so that the user does not see the standard and (to
them) confusing VBA error message.
• To rescue the situation and, if possible, correct things so that they can proceed
normally.
Before writing you error handler test your code thoroughly and try to spot places where
things could go wrong. If you manage to cause an error note the circumstances and the error
number that is displayed in the VBA error message.
In this exercise the most obvious errors would arise from the user making an invalid entry in
the Input Box. If the user typed a text entry error 13 (type mismatch) would occur because
the number they enter is being placed into a variable that has a numerical data type. If they
typed a very large number (greater than 32767) error 6 (overflow) would occur because the
variable's data type is Integer which accepts numbers in the range zero to 32767.
When your macro includes an error handler the first line of the macro should be a statement
directing the procedure to the error handler if an error occurs...
Step 27: Immediately below the line Sub MessageDemo() add the following line of code:
Step 28: Make a new line immediately above the line End Sub (the last line of the macro)
and enter the code:
MessageDemo_Err:
Note the colon (:) immediately following this text. This tells the Visual Basic Editor that this
text is a label and, if your code was indented, the Visual Basic Editor removes the indent so
that the label is flush with the left margin of the code window.
Just as the direction to the error handler is always the first statement in a macro, the error
handler itself is always placed right at the end. It is important that the procedure does not
continue into the error handler unless there has been an error so, to prevent this happening,
the procedure must be stopped before it gets there. To achieve this...
Step 29: Make a new line immediately above the MessageDemo_Err: label and enter the
statement:
Exit Sub
The statement Exit Sub works in the same way as End Sub and tells the procedure that it is
finished.
Now for the error handler itself. The On Error GoTo MessageDemo_Err statement at the
start of the macro instructs the macro to jump straight to the MessageDemo_Err: label
when an error occurs and proceed from there. At this point we will use a Case Statement to
check the identifying number of the error that just occurred and act accordingly...
Step 30: Insert the following code between the MessageDemo_Err: label and the End
Sub statement.
Responding to an error often involves more than just displaying a message and aborting the
procedure. If additional steps need to be taken the code can be added to the appropriate
part of the Case Statement. You could, for example, give the user another opportunity to
make an entry in the input box by placing a label immediately above the line of code that
displays the input box, and using a Resume statement in the Case Statement to direct the
macro to it.
Finally, and although not strictly necessary in this example, we are going to add an exit
routine to the error handler. Many macros end with a number of lines of "tidying up" code. If
specific processes are necessary because of an error they would be included in appropriate
parts of the Case Statement. But general processes that would have occurred even if the
error had not taken place would be missed if, following an error, the procedure moved
straight from the Case Statement to the End Sub statement.
This "tidying up" code would normally be placed at the end of the macro but before the error
handler, and immediately before the Exit Sub statement.
So that the procedure, after being dealt with by the error handler, can be directed back to
the "tidying up" code we add another label before it. As I mentioned earlier, this macro
doesn't have any "tidying up" code but even so it is good practice add an exit routine in case
some is added at a later date....
Step 31: Make a new line immediately above the Exit Sub statement and enter the label:
MessageDemo_Exit:
Finally insert the following code as the last line of the error handler, between the
End Select and End Sub statements:
Resume MessageDemo_Exit
That completes the code for the Exploring Message Boxes exercise. The final code listing is
shown below (see: Final Code Listing for the MessageDemo Macro on page 57).
Run the macro several times, making different choices from the message boxes you see. The
exercise has demonstrated some of the many different ways that message boxes and input
boxes can be used.
Sub MessageDemo()
On Error GoTo MessageDemo_Err
Dim i As Integer
Dim x As Integer
Dim Response As VbMsgBoxResult
Dim StartTime As Double
Dim MinNumber As Integer
i = 0
x = 0
Response = MsgBox("The computer can pick a number or " & _
"you can pick one yourself. Would you like to choose?" _
, vbQuestion + vbYesNoCancel, "Number required")
If Response = vbCancel Then
MsgBox "You chose to terminate the procedure." _
& vbCrLf & "The worksheet has not been altered." _
, vbInformation, "Macro Cancelled"
Exit Sub
ElseIf Response = vbYes Then
MinNumber = InputBox("The macro will look for numbers " _
& "greater than the number you choose." & vbCrLf _
& "Please enter a whole number between 1 and 999" _
, "Enter a number")
Else
Randomize
MinNumber = Int(Rnd * 1000)
MsgBox "The computer chose " & MinNumber, vbInformation _
, "Number Chosen"
End If
Range("A1").Select
Response = MsgBox("Would you like to time this operation?" _
, vbQuestion + vbYesNo)
StartTime = Timer
Do
If ActiveCell.Offset(i, 0).Value > MinNumber Then
ActiveCell.Offset(i, 0).Copy _
Destination:=ActiveCell.Offset(x, 1)
x = x + 1
End If
i = i + 1
Loop Until IsEmpty(ActiveCell.Offset(i, 0))
If Response = vbNo Then
MsgBox "The values have been copied into column B" _
, vbInformation, "Macro Complete"
Exit Sub
End If
Response = MsgBox("The procedure took " & Timer - StartTime _
& " seconds." & vbCrLf _
& "Would you like to see the statistics?" _
, vbQuestion + vbYesNo, "Macro Complete")
If Response = vbNo Then Exit Sub
MsgBox "The macro processed " & i & " rows." _
& vbCrLf & x & " values were found." _
, vbInformation, "Statistics"
MessageDemo_Exit:
Exit Sub
MessageDemo_Err:
Select Case Err.Number
Case 6
MsgBox "The number you entered was too large." & _
vbCrLf & "Your number must not exceed 32767." & _
© Martin Green www.fontstuff.com 57
VBA Message Boxes
START
YES NO
InputBox MsgBox
Enter a Computer
number chose...
MsgBox
Time the
macro?
YES NO
MsgBox EXIT
Macro SUB
complete
MsgBox EXIT
Time taken. NO SUB
See Stats?
YES
MsgBox EXIT
Show SUB
Statistics
The following table lists the VBA return values used to determine which message box button
was pressed by the user:
For further information and tutorials on these and other topics visit his Office Tips web site
at: http://www.fontstuff.com
For further copies of this document or for information regarding Martin Green's training,
development or authoring services please contact him at: training@fontstuff.com
Copyright
This document is copyright ©2005 Martin Green.
No part of this document may be copied, photocopied or reproduced in any form or by any
means without permission in writing from the copyright owner.
All trademarks, service marks, products or services are trademarks or registered trademarks
of their respective holders and are acknowledged by the author.
Limitation of Liability
Every effort has been made to ensure complete and accurate information concerning the
material presented in this document. However, the author cannot be held legally responsible
for any mistakes in printing or faulty instructions contained within this document. The author
appreciates receiving notice of any errors or misprints.
Information in this document is subject to change without notice. Companies, names and
data used in examples herein are fictitious unless otherwise noted.
This document is supplied for training and is intended to familiarise the user with the
operation of software programs. The author urges the user to review the manuals provided
by the software publisher regarding specific questions as to the operation of the programs.