Chapter 2. This Sounds Like BASIC, So Why Doesn’t It Look Familiar?

IN THIS CHAPTER

I Can’t Understand This Code

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.

Understanding the Parts of VBA “Speech”

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

Object.Method.

Parameter

Adverb

Lists parameters after the method. Separate the parameter name from its value with :=.

Property

Adjective

You can set a property activecell.height = 10 or query the value of a property x = activecell.height.

Is VBA Really This Hard? No!

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.

VBA Help Files—Using F1 to Find Anything

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.

  1. Open Excel and switch to the VB Editor by pressing Alt+F11. From the Insert menu, select Module (see Figure 2.1).

    Insert a new module in the blank workbook.

    Figure 2.1. Insert a new module in the blank workbook.

  2. Type the three lines of code shown in Figure 2.2. Click inside the word MsgBox.

    Click inside the word MsgBox and press F1.

    Figure 2.2. Click inside the word MsgBox and press F1.

  3. 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 the VBA help topics have been installed, you will get this screen.

    Figure 2.3. If the VBA help topics have been installed, you will get this screen.

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.

Using Help Topics

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).

Most help topics have an example.

Figure 2.4. Most help topics have an example.

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.

Highlight code in the help file and copy with Ctrl+C.

Figure 2.5. Highlight code in the help file and copy with Ctrl+C.

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.

Examining Recorded Macro Code—Using the VB Editor and Help

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).

Recorded code from example in Chapter 1.

Figure 2.6. Recorded code from example in Chapter 1.

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).

Help topic for the OpenText method.

Figure 2.7. Help topic for the OpenText method.

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.

Optional Parameters

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.

Defined Constants

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.

In the Immediate window of the VB Editor, query to see the true value of constants such as xlFixedWidth.

Figure 2.8. In the Immediate window of the VB Editor, query to see the true value of constants such as xlFixedWidth.

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).

Click the blue hyperlink to see all the possible constant values. Here, the ten possible xlColumnDataType constants are revealed in a new help topic.

Figure 2.9. Click the blue hyperlink to see all the possible constant values. Here, the ten possible xlColumnDataType constants are revealed in a new help topic.

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
The first step of the Text Import Wizard in Excel is covered by three parameters of the OpenText method.

Figure 2.10. The first step of the Text Import Wizard in Excel is covered by three parameters of the OpenText method.

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 2 of the Text Import Wizard is handled by the seven parameters of the OpenText method.

Figure 2.11. Step 2 of the Text Import Wizard is handled by the seven parameters of the OpenText method.

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.

The third step of the Text Import Wizard is fairly complex. The entire FieldInfo parameter of the OpenText method duplicates the choices made on this step of the wizard.

Figure 2.12. The third step of the Text Import Wizard is fairly complex. The entire FieldInfo parameter of the OpenText method duplicates the choices made on this step of the wizard.

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.

The TrailingMinusNumbers parameter comes from this Advanced Text Import Settings. If you had changed either of the separator fields, new parameters would have been recorded by the macro recorder.

Figure 2.13. The TrailingMinusNumbers parameter comes from this Advanced Text Import Settings. If you had changed either of the separator fields, new parameters would have been recorded by the macro recorder.

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).

Sometimes when you click in a VBA keyword and press F1, you must guess which help library to use.

Figure 2.14. Sometimes when you click in a VBA keyword and press F1, you must guess which help library to use.

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.

If you guess wrong, you are taken to a help topic that is completely off-topic. It is easy enough to try again.

Figure 2.15. If you guess wrong, you are taken to a help topic that is completely off-topic. It is easy enough to try again.

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.

The correct help topic for the End property.

Figure 2.16. The correct help topic for the End property.

Properties Can Return Objects

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.

Using Debugging Tools to Figure Out Recorded Code

The Visual Basic Editor features some awesome debugging tools. These are excellent for helping you see what a recorded macro code is doing.

Stepping Through Code

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).

Stepping into code allows you to run a single line at a time.

Figure 2.17. Stepping into code allows you to run a single line at a time.

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).

The first line of the macro is about to run.

Figure 2.18. The first line of the macro is about to run.

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).

Switching to Excel shows that the Invoice.txt file has indeed been imported.

Figure 2.19. Switching to Excel shows that the Invoice.txt file has indeed been imported.

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).

Verify that the End(xlDown).Select command worked as expected. This is equivalent to pressing the End key and then the down arrow.

Figure 2.20. Verify that the End(xlDown).Select command worked as expected. This is equivalent to pressing the End key and then the down arrow.

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).

The recorded macro code blindly moves to Row 14 for the Total row.

Figure 2.21. The recorded macro code blindly moves to Row 14 for the Total row.

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.

The Reset button in the toolbar stops a macro that is in Break mode.

Figure 2.22. The Reset button in the toolbar stops a macro that is in Break mode.

More Debugging Options—Breakpoints

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).

The large brown dot signifies a breakpoint.

Figure 2.23. The large brown dot signifies a breakpoint.

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).

The yellow line signifies that the breakpoint line is about to be run next.

Figure 2.24. The yellow line signifies that the breakpoint line is about to be run next.

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.

Backing Up or Moving Forward in Code

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.

The cursor as it appears when dragging the yellow line to a different line of code to be executed next.

Figure 2.25. The cursor as it appears when dragging the yellow line to a different line of code to be executed next.

Not Stepping Through Each Line of Code

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.

Querying Anything While Stepping Through Code

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.

Using the Immediate Window

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.

Queries (and their answers), which can be typed into the Immediate window while a macro is in Break mode.

Figure 2.26. Queries (and their answers), which can be typed into the Immediate window while a macro is in Break mode.

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).

Resizing the Immediate window.

Figure 2.27. Resizing the Immediate window.

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).

The Immediate window shows the results before the current line is executed.

Figure 2.28. The Immediate window shows the results before the current line is executed.

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).

There is no need to type the same commands over in the Immediate window. Place the cursor at the end of the previous command and press Enter.

Figure 2.29. There is no need to type the same commands over in the Immediate window. Place the cursor at the end of the previous command and press Enter.

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).

The prior answer ($E$14:$G$14) is shifted down, and the current answer ($1:$1) appears below the query.

Figure 2.30. The prior answer ($E$14:$G$14) is shifted down, and the current answer ($1:$1) appears below the query.

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).

After selecting all cells with Cells.Select, place the cursor after the query in the Immediate window and press Enter. The new answer is that the selected range is all rows from 1 to 1,084,576.

Figure 2.31. After selecting all cells with Cells.Select, place the cursor after the query in the Immediate window and press Enter. The new answer is that the selected range is all rows from 1 to 1,084,576.

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).

Delete part of a query, type something new, and press Enter. The previous answers are pushed down, and the current answer is displayed.

Figure 2.32. Delete part of a query, type something new, and press Enter. The previous answers are pushed down, and the current answer is displayed.

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.)

Querying by Hovering

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.

Hover the mouse cursor over any expression for a few seconds, and a ToolTip shows the current value of the expression.

Figure 2.33. Hover the mouse cursor over any expression for a few seconds, and a ToolTip shows the current value of the expression.

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.

Querying by Using a Watch Window

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).

Setting up a watch to see the address of the current selection.

Figure 2.34. Setting up a watch to see the address of the current selection.

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).

Without having to hover or type in the Immediate window, you can always see the value of watched expressions.

Figure 2.35. Without having to hover or type in the Immediate window, you can always see the value of watched expressions.

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).

After running another line of code, the value in the Watches window updates to indicate the address of the new selection.

Figure 2.36. After running another line of code, the value in the Watches window updates to indicate the address of the new selection.

Using a Watch to Set a Breakpoint

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.

Select Break When Value Changes in the bottom of the Edit Watch dialog.

Figure 2.37. Select Break When Value Changes in the bottom of the Edit Watch dialog.

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.

Using a Watch on an Object

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.

Setting a watch on an object gives you a + icon next to the glasses.

Figure 2.38. Setting a watch on an object gives you a + icon next to the glasses.

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.

Clicking the + icon shows a plethora of properties and their current values.

Figure 2.39. Clicking the + icon shows a plethora of properties and their current values.

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.

The Ultimate Reference to All Objects, Methods, Properties

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 to display the Object Browser.

Figure 2.40. Press F2 to display 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.

Select a class, and then a member. The bottom window tells you the basics about the particular member. Methods appear as green books with speed lines. Properties appear as index cards with a hand pointing to them.

Figure 2.41. Select a class, and then a member. The bottom window tells you the basics about the particular member. Methods appear as green books with speed lines. Properties appear as index cards with a hand pointing to them.

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).

Close the Object Browser and return to your code window by clicking this X.

Figure 2.42. Close the Object Browser and return to your code window by clicking this X.

Five Easy Tips for Cleaning Up Recorded Code

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.

Tip 1: Don’t Select Anything

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).

Select from here to here...

Figure 2.43. Select from here to here...

...and press the Delete key. This is basic “101” of cleaning up recorded macros.

Figure 2.44. ...and press the Delete key. This is basic “101” of cleaning up recorded macros.

Tip 2: Ride the Range from the Bottom to Find Last Row

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.

End+Down fails in the user interface if a record is missing a value. Similarly, End(xlDown) fails in Excel VBA.

Figure 2.45. End+Down fails in the user interface if a record is missing a value. Similarly, End(xlDown) fails in Excel VBA.

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)

Note

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.

Tip 3: Use Variables to Avoid Hard-Coding Rows and Formulas

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, seeUsing the Offset Property to Refer to a Range,” p. 65, in Chapter 3, “Referring to Ranges.”

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 & ")"

Tip 4: Learn to Copy and Paste in a Single Statement

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")

Tip 5: Use With...End With If You Are Performing Multiple Actions to the Same Cell or Range of Cells

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

Putting It All Together—Fixing the Recorded Code

 

Next Steps

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset