As I mentioned before, if you’ve taken a class in a procedural language such as BASIC or COBOL, you might be really confused when you look at VBA code. Yes, VBA stands for Visual Basic for Applications, but it is an object-oriented version of BASIC. Here is a bit of VBA code:
Selection.End(xlDown).Select Range("A14").Select ActiveCell.FormulaR1C1 = "'Total" Range("E14").Select Selection.FormulaR1C1 = "=SUM(R[-12]C:R[-1]C)" Selection.AutoFill_ Destination:=Range("E14:G14"),_ Type:=xlFillDefault
This code will likely make no sense to anyone who knows only procedural languages, and unfortunately, your first introduction to programming in school (assuming you are over 25 years old) would have been a procedural language.
Here is a section of code written in the BASIC language:
For x = 1 to 10 Print Rpt$(" ",x); Print "*" Next x
If you run this code, you get a pyramid of asterisks on your screen:
* * * * * * * * * *
If you’ve ever been in a procedural programming class, you can probably look at the code and figure out what is going on. I think that a procedural language is more English-like than object-oriented languages. The statement Print "Hello World"
follows the verb-object format and is how you would generally talk. Let’s step away from programming for a second and think about a concrete example.
If you were going to play soccer using BASIC, the instruction to kick a ball would look something like
“Kick the Ball”
Hey—this is how we talk! It makes sense. You have a verb (kick) and then a noun (the ball). In the BASIC code in the preceding section, you have a verb (print) and a noun (an asterisk). Life is good.
Here is the problem. VBA doesn’t work like this. No object-oriented language works like this. In an object-oriented language, the objects (the nouns) are most important (hence, the name: object oriented). If you are going to play soccer with VBA, the basic structure would be:
Ball.Kick
You have a noun—the ball. It comes first. In VBA, this is an object. Then you have the verb—to kick. It comes next. In VBA, this is a method.
The basic structure of VBA is a bunch of lines of code where you have
Object.Method
Sorry, this is not English. If you took a romance language in high school, you will remember that they used a “noun adjective” construct, but I don’t know anyone who speaks in “noun verb” when telling someone to do something. Do you talk like this?
Water.Drink Food.Eat Girl.Kiss
Of course not. That is why VBA is so confusing to someone who previously stepped foot in a procedural programming class.
Let’s carry the analogy on a bit. Imagine you walk onto a grassy field and there are five balls in front of you. There is a soccer ball, a basketball, a baseball, a bowling ball, and a tennis ball. You want to instruct the kid on your soccer team to
Kick the soccer ball
If you tell him kick the ball (or ball.kick
), you really aren’t sure which one he will kick. Maybe he will kick the one closest to him. This could be a real problem if he is standing in front of the bowling ball.
For almost any noun, or object, in VBA, there is a collection of that object. Think about Excel. If you can have a row, you can have a bunch of rows. If you can have a cell, you can have a bunch of cells. If you can have a worksheet, you can have a bunch of worksheets. The only difference between an object and a collection is that you will add an s to the name of the object:
Row becomes Rows
Cell becomes Cells
Ball becomes Balls
When you refer to something that is a collection, you have to tell the programming language to which item you are referring. There are a couple of ways to do this. You can refer to an item by using a number:
Balls(2).Kick
This will work fine, but it seems a dangerous way to program. It might work on Tuesday; but if you get to the field on Wednesday and someone has rearranged the balls, Balls(2).Kick
might be a painful exercise.
The other way is to use a name for the object. To me, this is a far safer way to go. You can say:
Balls("Soccer").Kick
With this method, you always know that it will be the soccer ball that it being kicked.
So far, so good. You know you can kick a ball, and you know that it will be the soccer ball. For most of the verbs, or methods, in Excel VBA, there are parameters that tell how to do the action. These act as adverbs. You might want the soccer ball to be kicked to the left and with a hard force. Most methods have a number of parameters that tell how the program should perform the method:
Balls("Soccer").Kick Direction:=Left, Force:=Hard
As you are looking at VBA code, when you see the colon-equals combination, you know that you are looking at parameters of how the verb should be performed.
Sometimes, a method will have a list of ten parameters. Some may be optional. Perhaps the Kick
method has an Elevation
parameter. You might have this line of code:
Balls("Soccer").Kick Direction:=Left, Force:=Hard, Elevation:=High
Here is the radically confusing part. Every method has a default order for its parameters. If you are not a conscientious programmer and you happen to know the order of the parameters, you can leave off the parameter names. The following code is equivalent to the previous line of code.
Balls("Soccer").Kick Left, Hard, High
This throws a monkey wrench into our understanding. Without the colon-equals, it is not obvious that we have parameters. Unless you know the parameter order, you might not understand what is being said. It is pretty easy with Left
, Hard
, and High
, but when you have parameters like the following:
WordArt.Add Left:=10, Top:=20, Width:=100, Height:=200
it gets really confusing to see:
WordArt.Add 10, 20, 100, 200
The preceding is valid code, but unless you know that the default order of the parameters for this Add
method is Left
, Top
, Width
, Height
, this code will not make sense. The default order for any particular method is the order of the parameters as shown in the help topic for that method.
To make life more confusing, you are allowed to start specifying parameters in their default order without naming them, and then all of a sudden switch to naming parameters when you hit one that does not match the default order. If you want to kick the ball to the left and high, but do not care about the force (you are willing to accept the default force), the following two statements are equivalent:
Balls("Soccer").Kick Direction:=Left, Elevation:=High Balls("Soccer").Kick Left, Elevation:=High
As soon as you start naming parameters, they have to be named for the remainder of that line of code.
Some methods simply act on their own. To simulate pressing the F9 key, you use this code:
Application.Calculate
Other methods perform an action and create something. For example, you can add a worksheet with
Worksheets.Add Before:=Worksheets(1)
However, because Worksheets.Add
actually creates a new object, you can assign the results of this method to a variable. In this case, you must surround the parameters with parentheses:
Set MyWorksheet = Worksheets.Add(Before:=Worksheets(1))
One final bit of grammar is necessary. Adjectives. Adjectives describe a noun. Properties describe an object. We are all Excel fans here, so I am going to switch from the soccer analogy to an Excel analogy midstream. There is an object to describe the active cell. Luckily for us, it has the very intuitive name of
ActiveCell
Let’s suppose that we want to change the color of the active cell to yellow. There is a property called InteriorColor
for a cell. It uses a complex series of codes, but you can turn a cell to yellow by using this code:
ActiveCell.Interior.ColorIndex = 6
Did I lose you? Can you see how this is so confusing? Again there’s the Noun-dot-Something construct, but this time it is Object.
Property
rather than Object
.Method
.
How do you tell them apart? Well, it is really subtle. There is no colon before the equals sign. A property is almost always being set equal to something, or perhaps the value of a property is being assigned to something else.
To make this cell color the same as cell A1, you might say
ActiveCell.Interior.ColorIndex = Range("A1").Interior.ColorIndex
Interior.ColorIndex
is a property. By changing the value of a property, you can make things look different. It is kind of bizarre—change an adjective and you are actually doing something to the cell. Humans would say, “Color the cell yellow.” VBA would say
ActiveCell.Interior.ColorIndex = 30
Table 2.1 summarizes the VBA “parts of speech.”
Table 2.1. The Parts of the VBA Programming Language
VBA Component | Analogous To | Notes |
---|---|---|
Object | Noun | |
Collection | Plural noun | Usually specifies which object: Worksheets(1). |
Method | Verb |
|
Parameter | Adverb | Lists parameters after the method. Separate the parameter name from its value with :=. |
Property | Adjective | You can set a property |
Knowing whether you are dealing with properties or methods will help you to set up the correct syntax for your code. Don’t worry if it all seems confusing right now. When you are writing VBA code from scratch, it is tough to know whether the process of changing a cell to yellow requires a verb or just an adjective. Is it a method or a property?
This is where the beauty of the macro recorder comes in. When you don’t know how to code something, you record a short little macro, look at the recorded code, and figure out what is going on.
This is a radically cool feature, but I might make you jump through hoops first. If you are going to write VBA macros, you absolutely must have the VBA help topics installed. The problem: The VBA help topics are not installed in the default Office install. Here is how to see whether you have it.
Open Excel and switch to the VB Editor by pressing Alt+F11. From the Insert menu, select Module (see Figure 2.1).
Type the three lines of code shown in Figure 2.2. Click inside the word MsgBox
.
With the cursor in the word MsgBox
, press the F1 key on the keyboard. If the VBA help topics are installed, you will see the help topic shown in Figure 2.3.
If instead you get a message saying that help is not available on this topic, you have to find the original CDs (or get your network administrator to grant rights to the installation folder) so that you can install the VBA help topics. Go through the process of doing a reinstall. During reinstall, select the custom install and be sure to select the VBA help files.
If you request help on a function or method, the help walks you through the various arguments available to you. If you browse to the bottom of most help topics, the help provides code samples under the Example heading. This section of each help topic is a great resource (see Figure 2.4).
It is possible to select the code, copy it to the clipboard by pressing Ctrl+C (see Figure 2.5), and then paste it into your module by pressing Ctrl+V.
After you record a macro, undoubtedly there will be objects or methods that you are not sure of. Insert the cursor in any keyword and press F1 to get help on that topic.
Let’s take a look at the code that was recorded when you followed along in the example in Chapter 1, to see whether it makes more sense now in the context of objects, properties, and methods. You can also see whether it’s possible to correct the errors brought about by the macro recorder.
Here is the first code that Excel recorded in the example in Chapter 1 (see Figure 2.6).
Now that you understand the concept of Noun.Verb or Object.Method, look at the first line of code. It says, Workbooks.OpenText
. In this case, Workbooks
is an object. OpenText
is a method. Click your cursor inside the word OpenText
and press F1 for an explanation of the OpenText
method (see Figure 2.7).
The help file confirms that OpenText
is a method or an action word. In the gray box is the default order for all the arguments that can be used with OpenText
. Notice that only one argument is required: FileName
. All the other arguments are listed as optional.
What happens if you skip an optional parameter? The help file can tell you. For StartRow
, the help file indicates that the default value is 1. If you leave out the StartRow
parameter, Excel starts importing at row 1. This is fairly safe. Look at the help file note about Origin
. If this argument is omitted, you inherit whatever value was used for Origin
the last time someone used this feature in Excel on this computer. That is certainly a recipe for disaster—your code may work 98 percent of the time, but immediately after someone imports an Arabic file, Excel will remember the setting for Arabic and assume this is what your macro wants if you don’t explicitly code this parameter.
Look at the help file entry for DataType
in Figure 2.7. The help file says that it can be one of these constants: xlDelimited
or xlFixedWidth
. The help file says that these are the valid xlTextParsingType
constants. These constants are predefined in Excel VBA. In the VB Editor, press Ctrl+G to bring up the Immediate window. In the Immediate window, type this line and press Enter:
Print xlFixedWidth
The answer appears in the Immediate window. xlFixedWidth
is the equivalent of saying “2” (see Figure 2.8). Ask the Immediate window to Print xlDelimited
. This is really the same as typing 1. Microsoft correctly assumes that it is easier for someone to read code that uses the somewhat English-like term xlDelimited
rather than 1.
If you were an evil programmer, you could certainly memorize all these constants and write code using the numeric equivalents of the constants. However, the programming gods (as well as the next person who has to look at your code) will curse you for this.
In most cases, the help file either specifically calls out the valid values of the constants, or offers a blue hyperlink that causes the help file to expand and show you the valid values for the constants (see Figure 2.9).
My one complaint with this excellent help system is that it does not identify which parameters may be new to a given version. In this particular case, TrailingMinusNumbers
was introduced in Excel 2002. If you attempt to give this program to someone who is still using Excel 2000, the code doesn’t run because it does not understand the TrailingMinusNumbers
parameter. This is a frustrating problem, and the only way to learn to handle it is through trial and error.
If you read the help topic on OpenText
, you can surmise that it is basically the equivalent of opening a file using the Text Import Wizard. In the first step of the wizard, you normally choose either Delimited or Fixed Width. You also specify the File Origin and at which row to start (see Figure 2.10). This first step of the wizard is handled by these parameters of the OpenText
method:
Origin:=437 StartRow:=1 DataType:=xlDelimited
Step 2 of the Text to Columns Wizard enables you to specify that your fields are delimited by a comma. We don’t want to treat two commas as a single comma, so Treat Consecutive Delimiters as One is unchecked. Sometimes, a field may contain a comma—for example “XYZ, Inc.” In this case, the field should have quotes around the value. This is specified in the Text Qualifier box (see Figure 2.11). This second step of the wizard is handled by these parameters of the OpenText
method:
TextQualifier:=xlDoubleQuote ConsecutiveDelimiter:=False Tab:=False Semicolon:=False Comma:=True Space:=False Other:=False
Step 3 of the wizard is where you actually identify the field types. In our case, we left all fields as General except for the first field, which was marked as a date in MDY (Month, Day, Year) format (see Figure 2.12). This is represented in code by the FieldInfo
parameter.
If you would happen to click the Advanced button on step 3 of the wizard, you have an opportunity to specify something other than the default Decimal and Thousands separator, plus the setting for Trailing Minus for negative numbers (see Figure 2.13). Note that the macro recorder does not write code for DecimalSeparator
or ThousandsSeparator
unless you change these from the defaults. The macro recorder does always record the TrailingMinusNumbers
parameter.
At this point, you can more or less see how just about every option that you do in Excel while the macro recorder is running corresponds to a bit of code in the recorded macro.
Here is another example. The next line of code in the macro is
Selection.End(xlDown).Select
You can click and get help for three topics in this line of code: Selection
, End
, and Select
. Assuming that Selection
and Select
are somewhat self-explanatory, click in the word End
and press F1 for help. A Context Help dialog box pops up, saying that there are two possible help topics for End
. There is one in the Excel library and one in the VBA library (see Figure 2.14).
If you are new to VBA, it can be frustrating to know which one to select. Take your best guess and click Help. In this case, the End help topic in the VBA library is talking about the End
statement (see Figure 2.15), which is not what we have here.
Close Help, press F1 again, and choose the End
object in the Excel library. This help topic says that End
is a property. It returns a Range
object that is equivalent to pressing End+Up or End+Down in the Excel interface (see Figure 2.16). If you click the blue hyperlink for xlDirection
, you will see the valid parameters that can be passed to the End
function.
In the discussion at the start of this chapter, I said that the basic syntax of VBA is Object.Method
. In this particular line of code, the method is Select
. The End
keyword is a property, but from the help file, you see that it returns a Range object. Because the Select
method can apply to a Range object, the method is actually appended to a property.
You might then assume that Selection
is the object in this line of code. If you click the mouse in the word Selection
and press F1, you will see that according to the help topic, Selection
is actually a property and not an object. In reality, the proper code would be to say Application.Selection
; however, when you are running within Excel, VBA assumes you are referring to the Excel object model, so you can leave off the Application object. If you were to write a program in Word VBA to automate Excel, you would be required to include an object variable before the Selection
property to qualify to which application you are referring.
In this case, the Application.Selection
can return several different types of objects. If a cell is selected, it returns the Range object.
The Visual Basic Editor features some awesome debugging tools. These are excellent for helping you see what a recorded macro code is doing.
Generally, a macro runs really fast. You start it, and less than a second later, it is done. If something goes wrong, you have no opportunity to figure out what it is doing. Using Excel’s Step Into feature, it is possible to run one line of code at a time.
Make sure the cursor is in the ImportInvoice
procedure and from the menu select Debug, Step Into, as shown in Figure 2.17 (or press F8).
The VB Editor is now in Step mode. The line about to be executed is highlighted in yellow with a yellow arrow in the margin before the code (see Figure 2.18).
In this case, the next line to be executed is the Sub ImportInvoice()
line. This basically says, “We are about to start running this procedure.” Press the F8 key to execute the line in yellow and move to the next line of code. The long code for OpenText
is then highlighted. Press F8 to run this line of code. When you see that Selection.End(xlDown).Select
is highlighted, you know that Visual Basic has finished running the OpenText
command. Indeed, you can press Alt+Tab to switch to Excel and see the Invoice.txt
file has been parsed into Excel. Note that A1 is selected (see Figure 2.19).
Switch back to the VB Editor by pressing Alt+Tab. The next line about to be executed is Selection.End(xlDown).Select
. Press F8 to run this code. Switch to Excel to see the results. Now A10 is selected (see Figure 2.20).
Press F8 again to run the Range("A14").Select
line. If you switch to Excel by pressing Alt+Tab, you will see that this is where the macro starts to have problems. Instead of moving to the first blank row, the program moved to the wrong row (see Figure 2.21).
Now that you have identified the problem area, you can either stop the code execution by using the Reset command (either by selecting Run, Reset or by clicking the Reset button on the toolbar; see Figure 2.22). After clicking Reset, you should return to Excel and undo anything done by the partially completed macro. In this case, close the Invoice.txt file without saving.
If you have hundreds of lines of code, you might not want to step through each line one by one. You might have a general knowledge that the problem is happening in one particular section of the program. In this case, you can set a breakpoint. You can then have the code start to run, but the macro breaks just before it executes the breakpoint line of code.
To set a breakpoint, click in the gray margin area to the left of the line of code on which you want to break. A large brown dot appears next to this code, and the line of code is highlighted in brown (see Figure 2.23).
Now, from the menu select Run, Run Sub or press F5. The program quickly executes but stops just before the breakpoint. The VB Editor shows the breakpoint line highlighted in yellow. You can now press F8 to begin stepping through the code (see Figure 2.24).
After you have finished debugging your code, remove the breakpoints. You can do this by clicking the dark brown dot in the margin to toggle off the breakpoint. You can also select Debug, Clear All Breakpoints or press Ctrl+Shift+F9 to clear all breakpoints that you’ve set in the project.
When you are stepping through code, you might want to jump over some lines of code. Or, perhaps you’ve corrected some lines of code and you want to run them again. In Step mode, it is easy to do this. My favorite method is to use the mouse to grab the yellow arrow. The cursor changes to an icon, meaning that you can move the next line up or down. Drag the yellow line to whichever line you want to execute next (see Figure 2.25). The other option is to click the cursor in the line to which you want to jump and then choose Debug, Set Next Statement.
When you are stepping through code, you might want to run a section of code without stepping through each line. This is common when you get to a loop. You might want VBA to run through the loop 100 times so that you can step through the lines after the loop. It is particularly monotonous to press the F8 key hundreds of times to step through a loop. Click the cursor on the line you want to step to and press Ctrl+F8 or select Debug, Run to Cursor.
We haven’t talked about variables yet (the macro recorder never records a variable), but you can query the value of anything while in Step mode.
Press Ctrl+G to display the Immediate window in the VB Editor. While the macro is in Break mode, you can ask the VB Editor to tell you the currently selected cell, the name of the active sheet, or the value of any variable. Figure 2.26 shows several examples of queries typed into the Immediate window.
When invoked with Ctrl+G, the Immediate Window usually appears at the bottom of the Code window. You can use the resize handle (above the blue Immediate title bar) to make the Immediate window larger or smaller (see Figure 2.27).
There is a scrollbar on the side of the Immediate window. You can use this to scroll backward or forward through past entries in the Immediate window.
It is not necessary to run queries only at the bottom of the Immediate window. Here is an example. In this case, I’ve just run one line of code. In the Immediate window, I ask for the Selection.Address
to ensure that this line of code worked (see Figure 2.28).
Press the F8 key to run the next line of code. Instead of retyping the same query, I can click in the Immediate window at the end of the line containing the last query (see Figure 2.29).
Press Enter, and the Immediate window runs this query again, displaying the results on the next line and pushing the old results farther down the window. In this case, the selected address is $1:$1
. The previous answer, $E$14:$G$14
, is pushed down the window (see Figure 2.30).
Press F8 four more times to run through the line of code with Cells.Select
. Again, position the cursor in the Immediate window just after Print Selection.Address
and press Enter. The query is run again, and the most recent address is shown with the prior answers moved down in the Immediate window (see Figure 2.31).
You can also use this method to change the query. Click to the right of the word Address
in the Immediate window. Press the Backspace key to erase the word Address
and instead type Rows.Count
. Press Enter, and the Immediate window shows you the number of rows in the selection (see Figure 2.32).
This technique is excellent when you are trying to figure out a sticky bit of code. I might find myself querying the name of the active sheet (Print Activesheet.Name
), the selection (Print Selection.Address
), the active cell (Print ActiveCell.Address
), the formula (Print ActiveCell.Formula
) in the active cell, the value of the active cell (Print ActiveCell.Value
, or Print ActiveCell
because Value
is the default property of a cell), and so on.
To dismiss the Immediate window, click the X in the upper-right corner of the Immediate window. (Ctrl+G does not toggle the window on and off.)
In many instances, you can hover your cursor over an expression in the code. Wait a second, and a ToolTip pops up showing you the current value of the expression. This is invaluable for you to understand when you get to looping in Chapter 5, “Looping and Flow Control.” And, it still will come in handy with recorded code. Note that the expression that you hover over does not have to be in the line of code just executed. In Figure 2.33, Visual Basic just selected Row 1 (making A1 the ActiveCell
). If I hover the cursor over ActiveCell.Formula
, I get a ToolTip showing me that the formula in the ActiveCell
is the word InvoiceDate
.
Sometimes the VBA window seems to not respond to hovering. Because some expressions are not supposed to show a value, it is difficult to tell whether VBA is not displaying the value on purpose or whether you are in the buggy “not responding” mode. Try hovering over something that you know should respond (such as a variable). If you get no response, hover, click into the variable, and continue to hover. This tends to wake Excel up from the stupor, and hovering will work again.
Are you impressed yet? I started the chapter complaining that this didn’t seem much like BASIC, but you have to admit that the Visual Basic environment is great to work in. These debugging tools are excellent.
In Visual Basic, a watch is not something you wear on your wrist. It allows you to watch the value of any expression while you step through code. Let’s say that in the current example, I want to watch to see what is selected as the code runs. I would set up a watch for Selection.Address
.
From the VB Editor Debug menu, select Add Watch.
In the Add Watch dialog, enter Selection.Address
in the Expression text box and click OK (see Figure 2.34).
A Watches window is added to the busy Visual Basic window. It is usually added at the bottom of the code window. I started running the macro, importing the file and pressing End+Down to move to the last row with data. Right after the Cells.Select
code is executed, the Watches window shows me that Selection.Address
is $A$10
(see Figure 2.35).
Press the F8 key to run the code Range("A14").Select
. The Watches window is updated to show the current address of the Selection
is now $A$14
(see Figure 2.36).
Right-click the glasses icon in the Watches window and choose Edit Watch. In the Watch Type section of the Edit Watch dialog, select Break When Value Changes (see Figure 2.37). Click OK.
The glasses icon has changed to a hand with triangle icon. You can now press F5 to run the code. The macro starts running lines of code until something new is selected. This is very powerful. Instead of having to step through each line of code, you can now conveniently have the macro stop only when something important has happened. A watch can also be set up to stop when the value of a particular variable changes.
In the preceding example, we watched a specific property: Selection.Address
. It is also possible to watch an object, such as Selection. In Figure 2.38, you have set up a watch on Selection. You get the glasses icon and a + icon.
By clicking the + icon, you can see all the properties associated with Selection. Look at Figure 2.39! You can now see more than you ever wanted to know about Selection. There are properties that you probably never realized were available. You can see that the AddIndent
property is set to False
, and the AllowEdit
property is set to True
. There are useful properties in the list—you can see the Formula
of the selection.
In this Watches window, some entries can be expanded. The Borders collection has a plus next to it. Click any + icon to see even more details.
In the VB Editor, press F2 to open the Object Browser (see Figure 2.40). The Object Browser lets you browse and search the entire Excel object library. I own a thick book that is a reprint of this entire object model from the Object Browser. It took up 409 pages of text. I’ve never used those 409 pages because the built-in Object Browser is far more powerful and always available at the touch of F2. I’ll take a few pages to teach you how to use the Object Browser.
Press F2 and the Object Browser appears where the code window normally appears. The topmost drop-down currently shows <All Libraries>. There is an entry in this drop-down for Excel, Office, VBA, each workbook that you have open, plus additional entries for anything that you check in Tools, References. Go to the drop-down and select only Excel for now.
In the left window of the Object Browser is a list of all classes available for Excel. Click the Application
class in the left window. The right window adjusts to show all properties and methods that apply to the Application object (see Figure 2.41). Click something in the right window like ActiveCell
. The bottom window of the Object Browser tells you that ActiveCell
is a property that returns a range. It tells you that ActiveCell
is read-only—an alert that you cannot assign an address to ActiveCell
to move the cell pointer.
We have learned from the Object Browser that ActiveCell
returns a range. Click the green hyperlink for Range
in the bottom window and you will see all the properties and methods that apply to Range objects and hence to the ActiveCell
property. Click any property or method and click the yellow question mark near the top of the Object Browser to go to the help topic for that property or method.
Type any term in the text box next to the binoculars and click the binoculars to find all matching members of the Excel library.
The search capabilities and hyperlinks available in the Object Browser make it far more valuable than an alphabetic printed listing of all of the information. Learn to make use of the Object Browser in the VBA window by pressing F2. To close the Object Browser and return to your code window, click the lower X in the upper-right corner (see Figure 2.42).
I apologize. We are nearly to the end of Chapter 2, and the crazy macro we recorded in Chapter 1 still doesn’t work. I am sure you want to get to the heart of the matter and find out how to make the recorded macro work. Here are five easy rules that will quickly have your code running fast and working well.
Nothing screams “recorded code” more than having code that selects things before acting upon them. This makes sense—in the Excel interface, you have to select Row 1 before you can make it bold.
However, in VBA we rarely have to do this. (There are a couple buggy features in charts where you do have to select the chart object to make the method work, but that’s an exception.) It is possible to directly turn on bold font to Row 1 without selecting it. The following two lines of code turn into one line.
Macro recorder code before being streamlined:
Rows("1:1").Select Selection.Font.Bold = True
After streamlining the recorded code:
Rows("1:1").Font.Bold = True
There are several advantages to this method. First, there will be half as many lines of code in your program. Second, the program will run faster.
After recording code, I literally highlight from before the word Select
at the end of one line all the way to the dot after the word Selection
on the next line and press Delete (see Figures 2.43 and 2.44).
It is difficult to trust data from just anywhere. If you are analyzing data in Excel, remember that the data is often coming from who-knows-what system written who-knows-how-long ago. The universal truth is that sooner or later, some clerk somewhere will find a way to break the source system and will manage to enter a record without an invoice number. Maybe it takes a power failure to do it, but invariably, we cannot count on having every cell filled in.
This is a problem when using the End+Down shortcut. This key combination does not take you to the last row with data in the worksheet. It takes you to the last row with data in the current range. In Figure 2.45, pressing End+Down would move the cursor to cell A6 rather than cell A10.
The better solution is to start at the bottom of the Excel worksheet and press End+Up. Now, this seems silly in the Excel interface because you can easily see whether you are really at the end of the data. But, because it is easy in Excel VBA to start at the last row, get in the habit of using this code to find the true last row:
Cells(Rows.Count, 1).End(xlUp)
From 1995 through 2006, Excel worksheets featured 65,536 rows. In the prior edition of this book, the coding style was to use Range("A65536").End(xlUp)
to find the last row. With the expansion to 1,048,576 rows, you might be tempted to use Range("A1048576").End(xlUp)
in Excel 2007.
However, Rows.Count
will return the number of rows in the active workbook. This covers the possibility that the workbook is in compatibility mode, or even the possibility that someone is running the code in Excel 2003.
The macro recorder never records a variable. They are very easy to use. They are discussed in more detail later; but just as in BASIC, a variable can remember a value.
My recommendation is to set the last row with data to a variable. I like to use meaningful variable names, so my favorite for this is FinalRow
:
FinalRow = Cells(Rows.Count, 1).End(xlUp).Row
Now that you know the row number of the last record, it is easy to put the word Total
in Column A of the next row:
Range("A" & FinalRow + 1).Value = "Total"
For simpler methods of referring to this range, see “Using the |
You can even use the variable when building the formula. This formula totals everything from E2 to the FinalRow
of E:
Range("E" & FinalRow + 1).Formula = "=SUM(E2:E" & FinalRow & ")"
Recorded code is notorious for copying a range, selecting another range, and then doing an ActiveSheet.Paste
. The Copy
method as it applies to a range is actually much more powerful. You can specify what to copy and specify the destination in one statement.
Recorded code:
Range("E14").Select Selection.Copy Range("F14:G14").Select ActiveSheet.Paste
Better code:
Range("E14").Copy Destination:=Range("F14:G14")
If you were going to make the total row bold, double underline, with a larger font and a special color, you might get recorded code like this:
Range("A14:G14").Select Selection.Font.Bold = True Selection.Font.Size = 12 Selection.Font.ColorIndex = 5 Selection.Font.Underline = xlUnderlineStyleDoubleAccounting
For four of those lines of code, VBA must resolve the expression Selection.Font
. Because you have four lines that all refer to the same object, you can name the object once at the top of a With
block. Inside the With...End With
block, everything that starts with a period is assumed to refer to the With
object:
With Range("A14:G14").Font .Bold = True .Size = 12 .ColorIndex = 5 .Underline = xlUnderlineStyleDoubleAccounting End With
Our goal by now is that you know how to record a macro. You can use help and debugging to figure out how the code works. You also have five tools for making the recorded code look like professional code.
The next chapters go into more detail about referring to ranges, looping, and the crazy (but useful) R1C1 style of formulas that the macro recorder loves to use. We also introduce you to 30 useful code samples that you can use.