In this chapter, you will:
Explore the benefits of working with VBA code
Learn how to read and understand VBA code
Discover the core basics of how to write your own macros
Get tips and guidance on ways to apply VBA basics for accomplishing a wide range of tasks
If you have any concerns about venturing into this chapter, take a deep breath and relax. You’ll be perfectly comfortable here. This thorough primer on Microsoft Visual Basic for Applications (VBA) is written for advanced Microsoft Office users, not for programmers.
I’m not a programmer, so I won’t treat you like one. The fact is that you don’t have to be a programmer to make effective use of VBA (or Office Open XML, as discussed in Chapter 24). Yes, I use VBA and Office Open XML to develop solutions for clients, but that just means I’m taking advantage of all the tools that Microsoft Word, PowerPoint, and Excel have to offer for creating documents. If you can learn to format a table, create styles, or create fields in Word; to write formulas or generate charts in Excel; or to customize masters in PowerPoint, you can learn VBA.
After years of avoiding VBA because it seemed technical and scary, I fell head over heels one day after I had no choice but to venture into the Visual Basic Editor for a client. I discovered how easy it is and how much you can do with VBA even with just a basic level of knowledge. But the most important discovery was how much of the VBA language I already knew just from being an advanced Microsoft Office user. Nearly all elements of VBA that are specific to a program are the names of features and tasks you already know from using that program. Keep in mind that VBA is just an additional way to work with, and expand the capabilities of, the programs you already know.
Beyond the program-specific feature and task names, most VBA language and structure is virtually identical across Word, PowerPoint, and Excel. So, the majority of what you’ll learn in this primer will apply to macros you may want to write in any of these programs. However, because this chapter assumes that this is your first introduction to writing VBA (or writing any programming language, for that matter), it uses one program for most examples, to avoid the confusion of trying to cover too much too fast. Because Word is the primary document production program for Microsoft Office, most examples throughout this primer use Word VBA. Once you’re comfortable with Word VBA, you can apply all of the basics you learn to VBA tasks in PowerPoint and Excel as well.
One of my favorite examples of when and why to use VBA if you’re not a programmer came up one evening at dinner with a friend. She had been up until 3 A.M. the night before cleaning up tables for a report that was due that day. It was a Word document containing 50 tables copied from Excel that needed to be cleaned up and reformatted. The task took her, a power user, about six hours. At just over seven minutes per table, that isn’t bad, but she wanted to know if there was a way she could have done it more quickly. She had created a few table styles and even recorded a macro for some of the formatting, but she still had click into each table to apply them and then manually take care of any unique elements for each table.
In reply to her question, I asked if she knew any VBA, and she looked at me as if I were insane. But then I told her that if she had known some basic VBA (just part of what you’ll learn in this primer, by the way), she could have accounted for most of the differences among her tables in one macro and then formatted all of them at once. The task would have taken about six minutes instead of six hours. As you can imagine, learning VBA no longer seemed like a crazy idea to her.
Of course, this timesaving example is just one of several types of situations where you can benefit from VBA. As you saw in a couple of simple examples in the Excel chapters of this book, you can often use a single line of code to save substantial time or even do things you can’t do through the features in the user interface. Or, to take things further, you might also use VBA to create customizations or automation for your documents and templates, such as custom dialog boxes that can help users complete form documents.
In general, the answer to the question of when to use VBA is the same as when to use any feature in the Microsoft Office programs—use it when it’s the simplest solution for the task at hand. In the case of VBA, however, you may also be able to use it when there doesn’t appear to be a solution for the task at all. VBA expands the capabilities of Word, PowerPoint, and Excel, so you might find yourself with easy answers to tasks that you didn’t even know were possible.
In Office 2010 and Office for Mac 2011, however, it’s important to ask yourself if VBA is still the simplest solution before you embark on a complex project. With the Office Open XML Formats, you can do some things in today’s Microsoft Office more easily using Office Open XML—such as automatically populating document content with data from other sources. Also, some functionality that would have required automation in the past can now be done with built-in features, such as using a content control in Word 2010 to display a custom building block gallery when you need a selection of boilerplate text options that can’t be deleted. However, VBA macros are still almost exclusively the way to go when you want to use automation to save time on repetitive or cumbersome tasks.
The easiest way to begin learning VBA is to record macros and then look at what you’ve recorded in the Visual Basic Editor. In the subsections that follow, we’ll use this method to help you become acquainted with how to read VBA code.
Macros can no longer be recorded in PowerPoint, but you can still write VBA macros in PowerPoint. Macros can be recorded and written in Word and Excel.
So, what is a macro? A macro is simply a set of commands that can be executed together, similar to a paragraph style. However, whereas a style is a collection of settings that you can apply at once, a macro is a collection of actions.
When you record a macro, every step you take is recorded, including moving your insertion point up or down or making a selection.
Experienced VBA users continue to find macro recording useful for learning how to accomplish new tasks in VBA. One thing we all run into at some point, however, is the fact that there are a few commands that can’t be recorded. For example, if you record a macro while adding items to the Quick Access Toolbar in Office 2010 or using the new Search In box above the Ribbon in Office 2011, your steps won’t be recorded. In some cases, a macro that can’t be recorded means that you can’t accomplish the task through VBA, but it doesn’t always. You can do a great many things when writing VBA that can’t be done by recording macros, such as applying a document theme (or, in the preceding example from Office 2011, automating Find and Replace tasks). Learn more about this later in this chapter, as well as how to get help for finding commands that can’t be recorded.
To begin recording a macro, on the Developer tab, in the Code group, click Record Macro. You can also access the Macro Recorder from the Status bar in Office 2010 or the Tools menu in Office 2011.
Once you click Record Macro, the Developer tab (or Status bar) icon changes to indicate that recording is in progress. The appearance of the button differs by program and where you access it. Click Stop Recording (accessible from the same location where you accessed the Record Macro feature) when you’ve finished recording the actions you need.
The ability to pause macro recording also becomes available on the Developer tab when macro recording is in progress.
Let’s try one together as an example. Say that you’re starting a new, long presentation document. Each page of the document needs to begin with Headings 1, 2, and 3, consecutively, followed by a paragraph of Normal text. The first several pages of that document will each begin with the text Company Overview—(including the em dash) in the Heading 1 paragraph, followed by different text on each page.
To save a bit of time, let’s record a macro for setting up these pages.
In the interest of using the simplest method for any task, set up your document as follows before recording the macro:
Set Style For Following Paragraph for Headings 1, 2, and 3 to the style that follows each heading at the top of every page. (Heading styles are followed by Normal style by default, so no change is needed for Heading 3.)
Add Page Break Before formatting to the Heading 1 style so that new pages start automatically when you apply Heading 1.
Even after taking these steps, you can still save time by setting up these pages using a macro.
See Also For help with the Style For The Following Paragraph feature used in this setup, see Chapter 8. For help with line and page break options such as Page Break Before, see Chapter 7.
With your insertion point at the top of the empty document, click Record Macro and then do the following:
In the Record Macro dialog box, type a name for your new macro. Macro names must start with a letter and can include letters, numbers, and the underscore character, but can’t include spaces or most special characters.
Notice, in the Record Macro dialog box, that recorded macros in Word are stored by default in the global template Normal.dotm. (In Excel, recorded macros are stored by default in the active workbook.)
In the Store Macro In list, you have the option to select any open document or template, including currently loaded global document templates in Word. For now, leave the default storage location and click OK to begin recording.
Apply Heading 1 style to the active paragraph.
Type Company Overview—. (To add the em dash, you can use the keyboard shortcut Ctrl+Alt+Hyphen in Word 2010 or Command+Alt+Hyphen in Word for Mac 2011. Note that you can only use the hyphen on the number keypad for this shortcut.)
Press Enter (Return) four times.
Because Style For Following Paragraph is set as needed for the first three heading styles, these four hard returns add paragraphs with the styles Heading 2, Heading 3, and Normal, consecutively, followed by an additional Normal paragraph. That additional Normal paragraph is where your insertion point will be when the macro starts to run again, so it will become Heading 1 style in the first step of the macro.
To run that macro, on the Developer tab, click Macros, select the macro you just recorded, and then click Run.
You could run this particular macro each time you need to set up a page, or run it as many times as you’ll need identical pages. Or, you could edit it to add even more functionality, such as automatically adding the number of pages you need. But, for the moment, let’s just look at this macro as an example to demonstrate how to read VBA code.
To view the macro you just recorded, on the Developer tab, click Macros. Then, select your macro from the Macro Name list and click Edit. This will open the Visual Basic Editor with your macro open on screen. Your screen should look something like Figure 23-1.
For now, focus on the macro itself—we’ll look at the different elements of the Visual Basic Editor shortly.
Sub stands for subroutine, which is basically just another term for macro. Every macro begins with Sub
and ends with End Sub
, as you see in the preceding example.
The first few lines below Sub
in Figure 23-1 have an apostrophe at the beginning of the line. These are comments. An apostrophe at the beginning of a line of VBA code tells the macro to skip this line. When you record macros, VBA automatically adds some comment lines, one of which includes the name of the macro, as you can see in Figure 23-1.
You can delete any line that begins with an apostrophe without damaging the macro. Be sure, however, not to delete the apostrophe and leave other text on the line that you don’t want to run as a VBA command. The apostrophe is what tells VBA to skip the line when the macro runs.
After the comment text, you see the commands that make up the steps of this macro. If you tried this for yourself and you see more lines of code in your macro than in this sample, ask yourself if you took other steps. If, for example, you made a typo in the Company Overview text and went back to correct it, that could have been recorded as a collection of several steps. Remember that when a macro is recorded, every keystroke is recorded. So, each time you use a different arrow key to move your insertion point, for example, you’ll get another line of code. Take a look again at the commands from the preceding macro.
Selection.Style = ActiveDocument.Styles("Heading 1") Selection.TypeText Text:="Company Overview-" Selection.TypeParagraph Selection.TypeParagraph Selection.TypeParagraph Selection.TypeParagraph
Notice that this code doesn’t include any unfamiliar terms, even if you’ve never seen a line of VBA code before. Selection, style, active document, type text, and type paragraph all refer to extremely basic Word tasks. The majority of program-specific terms in VBA will be similarly familiar, just from your experience with the program.
As you progress through this primer, you’ll come to understand how to construct the preceding lines of code and how you can write your own macros that are even simpler than recorded macros for accomplishing the same tasks.
To begin to work in the Visual Basic Editor, you need to understand how files work in VBA—that is, how macros are organized and stored. The following common items are the principal components you need to know:
A statement is a single command or action in a macro—that is, it’s a line of code. For example, Selection.Font.Bold = wdToggle
is a statement. As you’ll see in the section Writing, Editing, and Sharing Simple Macros, later in this chapter, when you think of VBA as a language, think of a statement as a sentence.
A procedure is essentially another way of referring to a macro, although there are other types of procedures as well, such as functions. A function is a procedure that returns a result.
A module is a collection of code. Think of a module as a code document. A module can contain several procedures. And, like documents, modules can be saved as files, copied, and shared.
A project is the collection of all modules and related VBA objects in your document, template, or add-in. A project might have one or several modules, as well as other elements such as UserForms (dialog boxes).
Companion Content All of the VBA elements discussed in this list are covered in this chapter, with the exception of UserForms. You can learn about creating and working with UserForms in the online companion content provided for this book. Once you master the VBA basics covered in this chapter, find information about the online companion content—and other resources for taking your work with VBA further—in the chapter conclusion.
Before you start working with VBA code, take a few minutes to settle in to your surroundings. To help you work more comfortably, the subsections that follow describe a bit about each component of the Visual Basic Editor that is identified in Figures Figure 23-2 (Word 2010) and Figure 23-3 (Word 2011).
The code window is where your procedures appear. This is where you type macros when writing code and where you find the macros you’ve recorded. Notice that the procedure list is at the top-right of the code window. From this list, you can quickly move to any procedure in the active module.
Also notice the view options at the bottom of the screen. When you have several macros in a module, it can be helpful to view them one at a time. Full Module view is the default, but you can change this setting and many others through the Options dialog box (Preferences in Office 2011).
See Also For more about setting preferences for the Visual Basic Editor, see the section Setting Up Your Workspace, later in this chapter.
Project Explorer is where you see the list of all VBA projects that are currently open or loaded. All open documents, as well as open or loaded document templates, appear here, whether or not they contain macros. You can collapse or expand a project to view the modules and objects that it contains.
Documents appear in this list whether or not they’re macro-enabled file formats. This is important to keep in mind because, if you add code to a document using an Open XML Format that ends with the letter x, you won’t be able to save the document with its code. Save the document with the equivalent file format that ends in the letter m to make sure your code will be saved along with the document or template.
A project has a Modules or Forms folder only if it contains code modules or UserForms. However, in Word and Excel, every project contains an Objects folder, such as the Microsoft Word Objects folder you see under each of the projects visible in Figures Figure 23-2 and Figure 23-3.
In Word, the Objects folder contains a document object referred to as ThisDocument. In Excel, it contains both a ThisWorkbook object and a sheet object for each existing sheet in the workbook. Some types of code (such as a type of procedure known as a document-level event) are added directly in the code window for the document object rather than in a module. However, you will often have projects that have no code added to the document objects.
The Properties window shown in Figures Figure 23-2 and Figure 23-3 doesn’t look like much, but don’t be fooled. For modules, the Properties window is generally used only to edit the module name. However, for some object types (such as UserForms), the Properties window becomes extremely important because it’s populated with many settings that you can edit directly within it, ranging from the height and width of a UserForm to the value to display on a form control (such as a text box or an option button).
To edit the name of a module in the Properties window:
Click into the name where it appears on either the Alphabetic or Categorized tabs.
Edit it as you would document text.
Module naming rules are the same as macro naming rules—no spaces or special characters, and the name must begin with a letter.
Press Enter (Return) to set it.
All names in VBA subscribe to a similar set of rules as the module name. Names must always start with a letter and can’t include spaces or most special characters. Most names are limited to 255 characters. However, module names can’t exceed 31 characters, and macro names added in the Record Macro dialog box are limited to 80 characters.
Note that, when you record macros, they’re always added to a module named NewMacros. You can rename that module if you like, but the next time you record a macro, a new module will be created with the name NewMacros.
You’ll find many settings that can be customized in the Options dialog box, available on the Tools menu in the Visual Basic Editor. (In Office 2011, this is the Preferences dialog box, available from the application name menu, such as Word.) I don’t recommend spending much time in this dialog box just yet, because you might not be familiar with many of the settings. However, it’s good to know that it’s there, because you are likely to need it. This primer will point out when settings can be customized in this dialog box.
Possible settings in the Options (or Preferences) dialog box include default behavior for a number of programming actions (such as the way you’re notified about errors in your code), the formatting for each type of text or notification you see in the code window (such as comment text or errors), and the way the window itself is arranged.
In addition to settings in the Options dialog box, notice that you can drag to resize panes in the Visual Basic Editor window (such as the Project Explorer or Properties window), and can close those you don’t need. In the Visual Basic Editors for Office 2010, you can also drag to dock or float panes.
Use the View menu to access any windows you’ve closed. If you’re unable to dock any window in an Office 2010 Visual Basic Editor, you can change the setting for that window on the Docking tab of the Options dialog box.
Companion Content All code samples shown throughout this section are available in procedures in a module named PrimerSamples.bas, available in the Chapter23 sample files folder online at http://oreilly.com/catalog/9780735651999.
See Also For help importing a module into your Visual Basic Editor, see the section Saving and Sharing Macros, later in this chapter.
One of the most important differences between macros you record and macros you write is that, when you record a macro, you need to select an object to act on it. But when you write macros, you can usually identify items to act on instead of selecting them. That apparently simple difference gives you tremendous power and flexibility. For example, you can write a macro to act on all tables in your document automatically, rather than recording a macro that you run from each table.
We’ve now reached the core of this primer. From creating a macro to reading and understanding essential VBA language constructs, the sections that follow progress in a logical order to help you learn in such a way that you can immediately put your knowledge into practice. Review the content under each heading and try the examples for yourself in the Visual Basic Editor. Be sure that you understand the content covered under each heading before progressing, and you’ll be using VBA comfortably before you know it.
Most of the features you’ll learn about in the following sections are programming basics. They’re written here specifically for VBA. However, should you ever want to learn another programming language, it’s useful to know that many of the concepts and terms used here are fairly standard across common programming languages.
Select the project (in Project Explorer) to which you want to add the module.
You can click any element contained in the project to select the project, such as the project name or the Modules folder (if one exists).
On the Insert menu, click Module.
You can also insert a module from the Insert icon on the Standard toolbar. Notice that this icon defaults to what you last inserted (such as a module or a UserForm). Click the arrow beside the icon to select a different item from the available options, as you see in Figure 23-4.
To rename the module, click into the name field in the Properties window, as mentioned earlier. Type the new module name and then press Enter.
Once you have a module in which to create your macros, you can just click in the code window and begin typing to create a macro. As you saw in the sample recorded macro, every macro begins with the term Sub
, followed by the name of the macro, and then followed by a pair of parentheses. Those parentheses can be used to hold instructions for the macro or information about references in the macro, but it’s rarely necessary to type anything between them for basic document production macros. Even if you type nothing between the parentheses, however, note that they are required.
Notice as well that every macro ends with the line End Sub
. Many types of instructions you’ll learn throughout this section are paired (such as With
and End With
, demonstrated under the upcoming heading Grouping Statements.).
When you type Sub plus a procedure name and then press Enter, VBA automatically adds the parentheses at the end of the first line and adds the End Sub
line. However, with most paired terms, the end term isn’t added for you. It’s good practice to always type both ends of a paired structure at the same time so that you don’t forget to do so later. When macros become longer or more complex, finding the missing end portion of a paired structure can be a frustrating use of your time.
So, to start a macro in your new module, type the following:
Sub MacroName
After you press Enter, the procedure will look like this:
Sub MacroName() End Sub
The statements that your macro comprises will go between these two lines.
Just as the languages you speak comprise nouns, verbs, adjectives, and other parts of speech, VBA comprises objects, properties, and methods. Think of objects as nouns, properties as adjectives, and methods as verbs.
An object is just that—it’s a thing that can be acted on.
A property is a characteristic of an object—something that describes the object, such as its size or style.
A method is an action you can perform on an object. For example, Save
and Close
are both available methods for the ActiveDocument
object.
The only difference between the sentence structure in a spoken language and in VBA is that, though a sentence always requires a noun and a verb, a VBA statement requires an object and either a property or a method. Let’s take a look at a few examples.
In the following statement, ActiveDocument
is an object and Save
is a method.
ActiveDocument.Save
In the following statement, Selection
is the object (referring to the location of the insertion point—the actively selected content) and Style
is a property of that selection. Heading 1
, in this case, is the value (the setting) for the indicated property.
Selection.Style = "Heading 1"
Objects are often used as both objects and as properties of other objects, depending on where they’re placed in a statement. In the following statement, Tables(1)
refers to the first table in the active document. Though a table is an object, it’s also used here as a property of the active document. Style
, in this statement, is a property of the specified table.
ActiveDocument.Tables(1).Style = "Table Normal"
Even though Tables(1)
in this case is a property of ActiveDocument
, it’s still an object. Notice that the style being set is a property of the specified table.
You don’t typically need to think about whether an object is being used as an object or a property, similar to distinguishing whether an -ing word (such as creating, editing, or dancing) is being used in a given sentence as a noun or a verb. What’s important to note is that many objects, such as a table, require a higher-level object to make the reference specific enough for VBA to understand. For example, you can’t write simply Tables(1).Style
to indicate the style of the first table, because VBA needs to know what range you’re referring to when you tell it to act on the first table. Otherwise, you might be referring to the first table in the document, the first table in the selection, or a number of other possible ranges. Just keep in mind that many objects can also be used as properties of other objects, because this will come in handy when you reach the Getting Help section later in this chapter.
Looking at the preceding list of examples, you might be wondering how you’re supposed to memorize every possible object, property, and method name in each program for which you need to learn VBA. Well, relax. You hardly need to memorize anything at all when it comes to program-specific terms. When you understand the concept of using objects, properties, and methods to create statements, and you remember what you already know (the features of the program you’re automating), you’ll learn the names of the particular objects, properties, and methods the same way you learn vocabulary in a spoken language—simply by using it.
The set of VBA vocabulary that’s specific to a given program is known as the program’s object model. The Visual Basic Editor in each program also contains a “dictionary” of sorts for that object model, known as the Object Browser. You can use the Object Browser (available from the View menu) to search for the correct terminology to use for a given feature, or to see what properties or methods are available to a given object. For example, Figure 23-5 shows the range of results you get when you use the Object Browser in the Word Visual Basic Editor to search for the term table.
Figure 23-5. Despite different organization, the Object Browsers in Office 2010 and Office 2011 look and function very much the same.
Notice in Figure 23-5 that the selected item in the search results is the table object. The heading Classes refers to items in an object model that can have an available set of members—such as objects or modules. Properties and methods are members of a specified class. Notice the headings Classes and Member Of ‘Table’ in the bottom panes of the Object Browser.
In both Office 2010 and Office 2011, the Object Browser dialog boxes are adjustable. If you don’t see all of the panes shown in Figure 23-5, you can just drag to expand them.
In the following list, also notice the icons used in the Object Browser to denote objects, properties, methods, or library. These will also be displayed while you’re writing code, as explained under the next heading. (All of these icons are the same in Office 2010 and Office 2011.)
(An object model is a type of library. For example, results shown in the Object Browser in Figure 23-5 are members of the Word library, which is the same as saying the Word object model.)
One of the main reasons you don’t have to memorize the object model for the program you’re automating is that the Visual Basic Editor often gives you the available options as you write. When you type an object, for example, followed by a period, you automatically see a list of properties and methods available to that object, as shown in Figure 23-7.
Notice the icons, shown earlier, that appear in this Auto List to indicate properties or methods. All the members of a given object (that is, all properties and methods available to that object) appear in the list.
To scroll through an Auto List, you can use the up or down arrows as well as the Page Up and Page Down keys. You can also begin to type the item you need, if you know at least the first characters, to move to that position in the list. For example, if you type t immediately after the period that follows ActiveDocument
, the list would move to the image you see in Figure 23-8.
When you select the item you need in the Auto List, press the Tab key to add the item to your statement. (You can also press the Spacebar instead of using the Tab key. However, doing so will add a space in your code after the selected item.) Note that, if you press Enter once an item is selected in an Auto List, you’ll get an error unless the selected item was the last required term in the statement.
In addition to objects, properties, and methods, most macros use other types of terms as well, including variables and constants (the latter of which is discussed in the section Using Constants, later in this chapter).
Variables are types of data that represent objects, statements, or other elements required in your code. They’re often used to save time and make code more efficient, such as using a single term in place of a statement that you have to reference several times. They are also handy when you need to refer to any instance of a given object type, rather than specifying an instance of an object. Consider the following examples.
If you need to refer to the full name (the FullName
property includes the file path) of the active document in a few places within your macro, you might want to declare a variable to represent it, as shown in the following statement:
myName = ActiveDocument.FullName
The name of the variable in this case is myName
. Once you’ve typed this statement in your macro, you can use the term myName
in place of ActiveDocument.FullName
wherever you need to use the full name of the document.
When you use loops (discussed in the section Looping Code, later in this chapter) to execute a command for several instances of an object, you might use a variable as a counter to help you accomplish that. For example, say you want to apply a specific table style to all tables in the document, as shown in the following code.
Dim myI as Integer For myInt = 1 To ActiveDocument.Tables.Count ActiveDocument.Tables(myI).Style = "Table Contemporary" Next
The preceding code uses a For…Next
loop, explained in the section Using For Each…Next and For…Next Loops, later in this chapter. However, notice how the variable myI
is used here.
First, you declare the variable as an integer. (Declaring variable data types is discussed in the upcoming section Declaring Variables.)
Then, the start of the loop (the line that begins with the word For
) tells the code to begin executing with the variable equal to the number 1 and run until the variable equals the number of tables in the document. Each time the loop executes, the number is automatically increased by 1.
Next, notice that the variable is used to denote the table number in the statement that applies the style to the table.
Using variables in place of a complete statement, or as counters, is a common, useful tool. Other uses of variables are demonstrated under applicable headings later in this chapter, including Using Conditional Structures as well as Looping Code.
For code that’s easier to read, follow, and edit, use intuitive variable names. Variable names can’t contain spaces and can’t be VBA terms used for any other purpose (such as the name of an object, property, or method). Keeping those requirements in mind, make your variable names as short as possible to save yourself work.
As you saw in the preceding examples, variables can be used to represent different types of information, such as numbers, text strings, or objects. Several variable data types are available, and you can even create your own. However, to help you keep things simple as you begin using variables, Table 23-1 lists commonly used variable data types.
Note For a complete list of data types supported in VBA and their definitions, search the topic “Data Type Summary” in Visual Basic Help, available from the menu bar in any Visual Basic Editor.
Table 23-1. Commonly used variable data types
Possible values | |
---|---|
True or False | |
An integer ranging from –32,768 to 32,767 | |
A long integer ranging from –2,147,483,648 to 2,147,483,647 | |
A scaled integer ranging from –922,337,203,685,477.5808 to 922,337,203,685,477.5807 | |
A text string, such as a VBA statement (text strings are relatively unlimited—they can reach up to approximately two billion characters in length) | |
Variant | A number or a text string (if you don’t specify the data type for a variable, it is a variant by default) |
You can also declare variables as specific types of objects (such as a table, a style, or a document). Variables declared as a specific object type are called object variables, and they offer additional benefits, discussed next.
When you specify a variable type, which is called declaring the variable, you can save time and reduce errors. For more complex macros, declaring variables is also important because undeclared variables default to the variant data type, which uses more storage space than other data types and thus creates more work for the program running your macro.
Additionally, when you require that variables be declared in your modules, VBA lets you know while you’re still working on your code if variables contain spelling errors that could cause an error when users run your macro.
See Also For more on this subject, see the section Running Macros and Compiling Projects, later in this chapter.
When you declare an object variable—that is, a variable declared as a specific type of object—VBA recognizes the object so that you get Auto Lists for completing statements that include the variable.
When you declare a variable as a particular data type, you must use it as that data type. For example, if you declare myI as a string, VBA won’t understand if you use it in a statement as if it were a number (such as For myI = 1 to ActiveDocument.Tables.Count
, as demonstrated earlier). Variables you want to use as numbers must be declared with an appropriate numeric data type (see the preceding table for the possible values available to different numeric data types). Similarly, to use a variable as a text string, you must set the value of that variable (the information after the equal sign) as either a VBA statement or a text string enclosed in quotation marks.
To declare a variable, use a Dim
statement. For example:
Dim myI as Integer Dim myName as String
Once you type the word as in a Dim
statement, you get an Auto List of available options to help you complete the statement, as shown in Figure 23-9.
To require variable declaration in a module, click in the very top of the module, type the words Option Explicit, and then press Enter. This statement is one of several that you can place at the top of a module to apply to all procedures in your module. Notice that, when you press Enter after typing this statement, a line appears beneath it, just as a line automatically appears between macros. This part of the module is known as the General Declarations section.
You can set the Visual Basic Editor to require variable declaration automatically whenever you create a new module, through the Options dialog box in Office 2010 or the Preferences dialog box in Office 2011. On the Editor tab of that dialog box, check Require Variable Declaration.
For Mac users, as mentioned earlier, the Preferences dialog box did not hold these kinds of customizations at the time of publication. If you experience this, just get into the habit of typing Option Explicit each time you create a module.
If you have multiple macros that need to refer to the same variables, you can declare them publicly for the entire project so that you don’t need to type out the declarations in each applicable macro.
To do this, type your variable declarations in the General Declarations section of any module in the project, and use the word Public
instead of the word Dim
to begin the statement. For example, the following statement makes myName
a string variable, and myI
an integer variable, available to all procedures in the project:
Public myName as String, myI as Integer
Note, however, that you must be in a procedure to assign a value to a variable. For example, you can declare myI
as an integer variable for use throughout the project, but the statement myI = 1
must appear inside a procedure. To use one set of variable values for multiple macros across all modules in your project, put all value assignments for public variables in one macro, and then access that macro from any procedure where you need to use those values.
See Also To learn how to do this, see the section Running One Macro from Another, later in this chapter.
In addition to the variables that you use in your macros, there is an object type named Variable
in the Word object model. These are known as document variables, because you use them to store information in the document that’s collected or created by your macros, rather than as a place to store data just while the macro is running—such as when you need the document to remember information from one use of a given macro to the next.
For example, in template automation projects I do for clients, I sometimes add document variables to store user preferences that are specific to the individual document, such as which of a selection of design choices the user wants for the active document. The document needs to store that information after the macro runs so that the user’s preferences are remembered the next time the design macros are used.
In Word, this type of information can be stored using either a document variable or a custom document property (which you’re most likely familiar with from the Document Properties dialog box). However, Excel and PowerPoint don’t offer a document variable object, so custom document properties are the way to go for storing document-level data in your workbooks and presentations.
In addition to document-level data, there are several ways to store data on the system level—that is, so that data can be accessed by your macros for use by more than an individual document. One of the easiest and most common methods is storing data in the Windows Registry (or, for Mac Users, in Library>Preferences).
As you can imagine, there are many uses for storing data in variables, document properties, or system-level resources such as the Registry. To explore this topic, use the Object Browser in your Visual Basic Editor to look up the Variable
object, the property named CustomDocumentProperties
, and the GetSetting
and SaveSetting
functions (the last two are functions used for storing data on the system level).
In addition to the variables that you can declare for use in your procedures, many items in the VBA object models include elements that use the same data types as variables to specify settings for that item. The elements, known as arguments (similar to arguments in an Excel formula), can be required or optional.
An argument might be as simple as the index number of an object to specify it within the collection, such as the third table in the active document, written as ActiveDocument.Tables(3)
. Or, it might be a series of parameters that define how an action is to be executed, as is commonly used for VBA methods. Take a look at a few examples.
When you use the FollowHyperlink
method of the Document
object in a statement, you get the options shown in Figure 23-10 in the Quick Info ScreenTip that appears after you type the open parenthesis following FollowHyperlink
.
Most of the arguments shown in Figure 23-10 are optional. Typically, optional arguments appear in brackets, but as you see here, that’s not always the case. You can’t follow a hyperlink without an address. This example is an exception.
In most cases, if an argument appears in parentheses but seems to be key information, a default value is used when the parameter is omitted. For example, Selection.Move
has parameters to define the unit
and count
by which to move the active selection. If those parameters are omitted, the default for unit
is a character and for count
is 1. So the insertion point is moved one character forward.
When you use the Add
method for a Table
object, you get the arguments shown in Figure 23-11.
The Add
method is used for many objects in Word, PowerPoint, and Excel. It has different arguments, of course, for each, depending on the type of object being added. For the Table
object, the range argument (that is, the location where you want the new table to appear), number of rows, and number of columns are required.
Notice that the required parameters here (those not inside brackets) specify particular data types. The range is an object variable (referring to the Range
object), and the number of rows and columns both use the long
data type (as noted in the Quick Info). Note that the optional AutoFit behavior setting is a variant (default) data type, but it requires a value from an available set of constants. Learn about constants in the upcoming section Using Constants.
The HomeKey
method, shown in Figure 23-12, is used with the Selection
object. It’s the VBA equivalent of using the Home key on your keyboard.
The two available arguments used here—both of which are optional and use the variant data type—determine how far your insertion point moves (Unit
) and whether the selection is extended (equivalent to holding the Shift key when you press the Home key) or your insertion point is simply moved to the new location. Both arguments require selections from a set of available constants, as we’ll discuss shortly in the Using Constants section.
There are two ways to specify most arguments in statements such as those in the preceding list of examples. The first approach is to type the values for the arguments between parentheses immediately following the method (as you saw in the Quick Info ScreenTips for the three sample methods shown in Figures Figure 23-10 through Figure 23-12). When you use this approach, type a comma after each value you add. You’ll see that the active argument (the one for which you can add a value at your insertion point) is shown as bold in the ScreenTip. If you don’t intend to include a value for each argument, type consecutive commas until the argument you want to specify is bolded. If you place an argument in the wrong position between parentheses, the method won’t work correctly. Notice, however, that this approach can be confusing and difficult to read when you need to edit or troubleshoot a macro.
Some types of arguments can be specified simply in quotation marks after the statement name, as with the SaveSetting
function demonstrated previously in the sidebar Storing Data on the System.
Instead, for methods that take more than a single argument, specify each by typing the argument name, followed by a colon and an equal sign, followed by the value you want to assign. Separate each argument you specify with a single comma, and note that argument order doesn’t matter when you use this approach. Take a look at the following two examples:
ActiveDocument.FollowHyperlink Address:="http://office.com", NewWindow:=True Selection.HomeKey Unit:=wdStory, Extend:=wdExtend
Using the explicit approach shown here helps to keep your code easy to read, edit, and troubleshoot.
See Also Learn how to find the help you need in the section Getting Help, later in this chapter.
As mentioned previously, many items in VBA require the use of another data type, known as a constant. Unlike variables that can change as needed, constants are used when a defined set of options exists for the feature. Most constants in VBA are either specific to the individual program object model or are available in VBA for any Microsoft Office program.
It’s possible to define your own constants in VBA as well. However, the discussion of constants in this chapter is limited to built-in constants, generally referred to as intrinsic constants.
Constants specific to the Word object model start with the letters wd; those specific to the Excel object model start with the letters xl; those specific to PowerPoint start with pp; and those for use across the Microsoft Office programs start with mso. There are also sets of constants that are specific to the Visual Basic language and available to VBA in all of the Microsoft Office programs—these constants begin with the letters vb.
Because constants are defined members of an object model, you can search for them in the Object Browser. For the purposes of searching the Object Browser, note that a set of constants is considered an enumeration class, and the constants within that enumeration are the members of that class. Sets of available constants for a given argument are also usually easy to find through VBA help. Additionally, Auto Lists are available for many constant sets, particularly object and property constants. Take a look at a few examples.
The Type
property of the Field
object is available as a set of constants, provided in an Auto List when you type a valid statement for using this property. The example shown in Figure 23-13 is the beginning of a conditional statement.
See Also Learn about conditional statements in the section Using Conditional Structures, later in this chapter.
Note that available constants might differ by platform or application. For example, the field type list in Figure 23-13 shows Word 2010 field types. Most, but not all, field types are available in both Word 2010 and Word 2011.
Because different header or footer types are available in each section, the Header
and Footer
objects have a set of constants from which to select when you use those objects, as you see in Figure 23-14.
The first macro you saw in this primer (in the section Recording Macros) recorded four consecutive statements for adding four paragraphs to the document. If you had written that macro instead, you could have used the constant vbCr
, which is the VBA constant to indicate a carriage return. In that case, that first macro could have been written with the following code, in just two statements instead of six:
Selection.Style = ActiveDocument.Styles("Heading 1") Selection.TypeText("Company Overview-" & vbCr & vbCr & vbCr & vbCr)
The ampersand (&) is used to combine the text and constant portions of the text string, just as you can do to combine text, functions, and cell references into a text string in Excel. Learn more about using operators in VBA in the section Using Operators, later in this chapter.
Many arguments for different methods use the same sets of constants, which often are not available in Auto Lists, but are still easy enough to find. For example, the HomeKey
method shown earlier uses constants for both of its arguments. The Unit
argument uses the wdUnits
set of constants; the Extend
argument uses the wdMovementType
set of constants.
The easiest way to learn which constant set you need is to search VBA help for the applicable method. This is because, in some cases, not all members of a constant set are available to all methods that use those constants. For example, wdUnits
includes 16 constants, but only 4 are available when used with the HomeKey
method. (The four available in this case are wdLine
[the default if you don’t specify the argument], wdStory, wdRow
, and wdColumn
—the last two of which apply only when your selection is in a table.) If you searched for the HomeKey
method in VBA help, you’d see information about the available constants for both arguments.
See Also Note that the upcoming Getting Help section shows you how to use the Object Browser and VBA help reference together to save time. Comprehensive VBA help might not appear to be available in Office 2011, but Mac users, take heart—the Getting Help section provides an easy solution.
Objects for which there can be many instances of the object type within a given scope are available as both an object and a collection object. A collection comprises all instances of a given object type within the specified scope. This distinction is important because the object and its collection object can have very different members (that is, a very different set of available properties and methods). For example, compare the two statements that follow:
Documents(1).Tables.Count Documents(1).Tables(1).AllowAutoFit = True
The first of the two preceding statements uses the Tables
collection object. The second uses the Table
object, specifying the first table in the collection. Both statements also use the Document
object, specifying the first document in the Documents
collection. (Note that the Documents
collection in the Word object model refers to all currently open documents. The first document in the collection refers to the most recently opened document.)
The Table
object has a very broad set of members, as you see in Figure 23-16. It’s used whenever a single object is being referenced from the collection. Notice that only a fraction of this object’s member list is visible in a single screen.
In contrast, the Tables
collection object has very few members (shown in Figure 23-17), including only those items that can apply to the entire collection at once.
Say that you’re in a restaurant and you need three things from the waiter. If you ask for some ketchup, then ask for a glass of wine when the waiter drops off your ketchup, and then ask for a glass for your friend when the waiter returns with your wine, that’s a lot of work for the waiter (not to mention, he might be tempted to sneeze in your soup).
Instead, if you say to the waiter, “I need some ketchup, please. I’d also like another glass of wine, and my friend will have one as well,” you’ve given the waiter three tasks that he can execute together. That is, you’ve just grouped a set of statements (and saved yourself from a possible cold).
Though VBA won’t sneeze in your soup, macros do run more slowly when you force the program to execute several related tasks independently. Grouping related statements together helps make your code more efficient (and saves you time writing code, because you’ll be writing less).
Statements can be grouped using the With…End With
structure, as you saw in the recorded macro example in the earlier sidebar, Why Does My Recorded Macro Have So Many Lines of Code, When I Did Only One Thing? You can use With…End With
anywhere that two or more statements apply to the same object, or the same combination of objects, properties, and methods. For example, the very first macro we looked at in this chapter contains six statements, all of which apply to the Selection
object. So, if you had written that macro instead of recording it, you could have typed the following:
With Selection .Style = "Heading 1" .TypeText "Company Overview-" & vbCr & vbCr & vbCr & vbCr End With
Recorded macros will sometimes include lengthier statements than are necessary when you write the macro. This is typically because a recorded macro often explicitly states defaults that are assumed if omitted. For example, in the recorded version of this macro, the style was applied with the statement Selection.Style = ActiveDocument.Styles(“Heading 1”)
. However, a style is applied using the style definition in the active document by default. So when written, as you see in the preceding code, that information can be omitted.
Though you might not be saving much by grouping statements when the macro is just two lines long, imagine something a bit lengthier. For example, say that you wanted to do several things to the first table in the document. Instead of starting each line with ActiveDocument.Tables(1)
, you can group the statements using a With…End With
structure, as follows:
With ActiveDocument.Tables(1) .Style = "Table Contemporary" .Range.Style = "Table text" .Columns(4).Shading.ForegroundPatternColor = wdColorLavender .Rows(1).Range.Style = "Table heading" .Rows(1).HeadingFormat = True End With
In fact, you can take that grouping a step further. Notice that the first row of the table is referred to more than once. You can add a nested With…End With
structure for those rows as follows:
With ActiveDocument.Tables(1) .Style = "Table Contemporary" .Range.Style = "Table text" .Columns(4).Shading.ForegroundPatternColor = wdColorLavender With .Rows(1) .Range.Style = "Table heading" .HeadingFormat = True End With End With
With grouping structures, just remember that all items in the With
statement must apply to all statements between With
and End With
, if the statement starts with a period (which indicates that it uses the object referred to in the With
statement). For example, you can do some things directly to the Row
object that you can’t do directly to the Column
object, such as applying a style. In that case, you might want to first select the column for which you need to apply a paragraph style, as you see here:
With ActiveDocument.Tables(1) .Style = "Table Contemporary" .Range.Style = "Table text" With .Columns(4) .Shading.ForegroundPatternColor = wdColorLavender .Select End With Selection.Style = "Table Subheading" With .Rows(1) .Range.Style = "Table heading" .HeadingFormat = True End With End With
In the preceding code, Selection.Style
doesn’t have to refer to the object in the With
statement, because it isn’t using that object.
As mentioned earlier in this chapter, remember that With…End With
structures (as well as the code structures described in the upcoming section Looping Code) require a pair of statements. For ease of editing and to reduce errors, whenever you type the first part of the structure (the With
statement, in this case), type its paired closing statement (End With
) as well, so that you don’t forget to do so later.
If I had to pick one feature of VBA that’s the most useful on a daily basis for document production and document troubleshooting, it would be loops. Loops enable you to act on several instances of a given object within one macro. Fortunately, as much as loops can do for you, they’re also extremely easy to use.
In this primer, we’ll look at variations on two of the most common types of loops, For
loops and Do
loops.
A For Each…Next
loop enables you to act on all instances of a given object within a specified range. For example, you might use this type of loop to format all tables in your document at once or to change the fill color of all text boxes in your document to a particular theme color. Similarly, a For…Next
loop enables you to specify a range of instances of the given object on which you want to act. For example, say that all tables in your document other than the first five need to have the same formatting. You can use a For…Next
loop to specify that the formatting should apply to only those tables you want.
To use a For Each…Next
loop, start by declaring a variable of the object type upon which to act and then use that variable in your loop. Take a look at the code for the two examples given in the preceding paragraph.
Apply the style Table Contemporary to all tables in your document.
Dim atb as Table For Each atb in ActiveDocument.Tables atb.Style = "Table Contemporary" Next atb
The use of atb
as the variable name for the table object is just a personal choice. As mentioned earlier in this chapter, you can use any name for a variable that meets VBA naming requirements (no spaces and a letter for the first character) and isn’t the name of any member of an available object model.
Remove any user-defined styles from the active document.
Dim ast as Style For Each ast in ActiveDocument.Styles If ast.BuiltIn = False Then ast.Delete End If Next ast
Specifying the variable in the Next
statement, as shown in both preceding examples, is optional. However, it’s good practice to do this to avoid confusing the statements you need to keep or alter when you edit a macro, particularly when you use multiple loops in the same procedure.
To use a For…Next
loop, start by declaring a numeric variable data type to use for counting the instances upon which you want to act. Following is the code for the example given earlier (formatting all but the first five tables in the document).
Dim myI as Integer For myI = 6 to ActiveDocument.Tables.Count ActiveDocument.Tables(myI).Style = "Table Contemporary" Next myI
Notice that I could have used a With…End With
structure instead of retyping ActiveDocument
each time I needed it. Of course, that would be more helpful if I were doing more than just applying a table style, as you see in the following example:
Dim myI as Integer With ActiveDocument For myI = 6 to .Tables.Count With .Tables(myI) .Style = "Table Contemporary" .AutoFitBehavior (wdAutoFitWindow) End With Next myI End With
In the preceding code, notice that I use the For…Next
loop with nested With…End With
structures to make this macro as efficient as possible to write, and as efficient as possible for Word to execute.
A Do
loop, aside from being fun to say, can be another useful way of creating a loop for specified instances of an object. (Note that this type of loop is usually referred to as a Do…Loop
structure, which helps to clarify the fact that, like For…Next
loops or With…End With
structures, a Do…Loop
actually requires a pair of statements.)
Do…Loop
structures can either be executed while a qualification is true or until a qualification becomes true. Similar to For…Next
loops, a Do While…Loop
is usually used with a numeric variable. A Do Until…Loop
may be used with a numeric variable or until a given condition is true. Take a look at a couple of examples.
Say that you’re troubleshooting a document. Using Open And Repair in Word 2010, you find that a floating object is causing the unstable document behavior. However, you don’t see any floating objects in the document (this would happen if floating objects were off the page, or hidden behind opaque document elements because of the Behind Text wrapping style). Using a Do…Loop
, you can delete all floating objects in the body of the document, as follows:
With ActiveDocument Do Until .Shapes.Count = 0 .Shapes(1).Delete Loop End With
In the preceding code, notice that ActiveDocument.Shapes(1)
refers to the first shape in the document. In this case, you wouldn’t use a For…Next
loop with a counter, because each time a shape is deleted, the shape object reference .Shapes(myI)
would refer to a different object. Instead, if you continually delete the first shape until there are no more shapes, you don’t need to be concerned with the way VBA counts the shapes in the document as their number is being reduced.
In the case of deleting all shapes in a document, you may wonder why a For Each…Next
loop wasn’t used, since we want to act on all instances of shapes in the document. For Each…Next
loops are an easy solution in most cases that require acting on all instances of an object type. However, there are two reasons why the Do…Loop
was the better choice here. First, there’s less code with a Do…Loop
in this case because you don’t need to declare the object variable before executing the loop. Second, there’s an anomaly when you use a For Each…Next
loop specifically to delete floating graphics (that is, members of the Shapes
collection object), and one or more shapes may be left behind. Using the Do…Loop
structure instead ensures that all shapes are deleted.
The following code uses a Do While…Loop
instead of a For…Next
loop for formatting all tables other than the first five with the Table Contemporary style and AutoFit To Window behavior.
Dim myI as Integer myI = 6 With ActiveDocument Do While myI <=.Tables.Count With .Tables(myI) .Style = "Table Contemporary" .AutoFitBehavior (wdAutoFitWindow) End With myI = myI + 1 Loop End With
Notice in the preceding code that the integer variable was set to start counting at six, so the first five tables in the document would be ignored. The Do While
statement says to execute the code in the loop while the integer value is less than or equal to the number of tables in the active document. Then, at the bottom of the commands that fall within the loop, you see a counter for the integer variable to increase the number by one with each iteration of the loop.
In the first of the two preceding examples, a Do…Loop
structure is a better choice than a For…Next
loop (as explained in the text that follows that sample code). However, in the second example, a For…Next
loop would have been the more efficient choice. Notice that, in the second example, if you use a For…Next
loop, you don’t need a separate statement for the counter—the For
statement is a built-in counter.
So, how do you decide whether to use a For…Next
loop or a Do…Loop
structure? You just need to ask yourself a few simple questions, as follows (and as summarized in Figure 23-18).
I wish I had conceived the questions that follow, but I can’t take the credit. Many thanks to Beth Melton, who was the technical reviewer for the first version of this primer and for sharing her clear and concise approach to this topic (and others).
Do you know the number of repetitions you need in the loop?
As demonstrated by the preceding code samples in this section, if the answer is yes, use a For…Next
loop. If the answer is no, use a Do…Loop
.
If you’re using a Do…
Loop structure, is the condition initially true?
If the condition is initially true, you need a Do While
statement to begin your loop. If, on the other hand, the loop needs to execute until the condition becomes true, start your loop with a Do Until
statement.
There’s one more factor to consider when deciding on the loop type you need. You can evaluate the condition specified in a Do…Loop
structure either at the top of the loop (as shown in the earlier example of a Do While…Loop
structure) or at the bottom of the loop (with a Do…Loop Until
or Do…Loop While
structure).
A top evaluation loop is structured as follows:
Do While <condition> <statements> Loop
A bottom evaluation loop, on the other hand, looks like this:
Do <statements> Loop While <condition>
(Remember, in the preceding structures, to substitute Until
for While
if you need to execute the code until the condition becomes true.)
So, to determine whether you need a top or bottom evaluation loop, ask the following question: must the code execute at least once?
If the code must run at least once for your macro to do what you need, use a bottom evaluation loop so that the condition isn’t evaluated until after the first time the code runs. If the code doesn’t have to run at least once, use a top evaluation loop so that the condition is evaluated before the first time the code runs. For example, in the sample Do…Loop
structure shown earlier—in which the loop is used to delete all shapes from the active document—a top evaluation loop is appropriate, because the code doesn’t need to run if the document contains no shapes from the outset.
As demonstrated with For…Next
and Do…Loop
structures, there are several ways to apply conditions to the commands you want to execute with VBA. Frequently, however, the condition you need may be something other than the instances of an object. Conditional structures in VBA, other than loops, are formed using either the paired If and End If
statement or the Select Case…End Select
statement.
Much like the IF function in Excel and the IF field in Word, If…End If
structures in VBA are used for executing actions when specified criteria are met. Take a look at the following examples:
Say that you’re creating automation to format new business presentation documents. Your branding specifies that any presentation of longer than three pages should use landscape orientation. If the user clicks the button to use your formatting macro, you may want the macro to first check the length of the document and then set the orientation to landscape if the document exceeds three pages.
With ActiveDocument If .RangeInformation(wdActiveEndPageNumber) > 3 Then .PageSetup.Orientation = wdOrientLandscape End If End With
Say that you’re applying a template to a document that uses only built-in Word styles, such as Normal and Headings 1–9. Once you’ve reformatted the document content as needed, you may want to clean up the document styles to help ensure that the document continues to be formatted with the styles you want. The following code removes any styles from the document that are not built in:
Dim ast As Style For Each ast In ActiveDocument.Styles If ast.BuiltIn = False Then ast.Delete End If Next ast
If…End If
structures are often used with multiple conditions, such as when you want to set one value if the condition is true and another if it’s false, as you see in the following example:
With ActiveDocument If .Range.Information(wdActiveEndPageNumber) > 3 Then .PageSetup.Orientation = wdOrientLandscape Else .PageSetup.Orientation = wdOrientPortrait End If End With
The preceding example adds an extra qualifier to the similar code shown earlier, so that if the document is three pages or shorter, your macro ensures that the document uses portrait orientation.
If
statements can also contain multiple conditions by including ElseIf
statements. For example, say that you have many tables in your document with different layouts, but all financial tables have either four or six columns. Those financial tables with four columns should use the custom table style named Table Financial 4, those with six columns should use the style named Table Financial 6, and all other tables in the document should be formatted using Table Normal style.
Dim atb As Table For Each atb In ActiveDocument.Tables With atb If .Columns.Count = 4 Then .Style = "Table Financial 4" ElseIf .Columns.Count = 6 Then .Style = "Table Financial 6" Else .Style = "Table Normal" End If End With Next atb
Notice that both If
and ElseIf
statements require Then
at the end of the line. Also notice that, regardless of the number of conditions in an If
statement, End If
is still required at the end of the complete structure.
For simple If
structures where there is a single condition, you can get an exception to the paired statement requirement. You can often add just a single statement on one line and leave off the End If
statement. For example, the If…End If
statements in the first two examples given earlier could have been written on a single line.
Dim ast As Style For Each ast In ActiveDocument.Styles If ast.BuiltIn = False Then ast.Delete Next ast
Although If
structures are the most common conditional structure used in VBA, Select Case
can be an extremely efficient alternative in some situations, so it is definitely worth a look.
Here, Select Case
is used for one of the previous If
statement examples:
Dim atb As Table For Each atb In ActiveDocument.Tables With atb Select Case .Columns.Count Case 4 .Style = "Table Financial 4" Case 6 .Style = "Table Financial 6" Case Else .Style = "Table Normal" End Select End With Next atb
For this code, the If
structure and Select Case
structure are very similar and essentially equally good choices. Where Select Case
can be more useful is when several options meet a given condition.
For example, say that a long report document has been through a lot of hands and had content copied and pasted from several sources, and now you want to go through it and quickly clean up the styles. Perhaps you want to replace the style for paragraphs formatted with a number of different body text styles with Normal style, and replace the use of a few custom heading styles with the Heading 1 style. Notice in the code that follows that multiple options for a given case are separated by commas.
Dim myI As Integer myI = 1 With ActiveDocument For myI = 1 To .paragraphs.Count With .paragraphs(myI) Select Case .Style Case "Body Text", "Body Text 2", "Body Text 3" .Style = "Normal" Case "Body Heading", "Document Heading", "Page Heading" .Style = "Heading 1" End Select End With Next End With
If you used an If
statement instead of Select Case
here, the code would be as follows:
Dim myI As Integer myI = 1 With ActiveDocument For myI = 1 To .paragraphs.Count With .paragraphs(myI) If .Style = "Body Text" Or .Style = "Body Text 2" Or .Style = "Body Text 3" Then .Style = "Normal" ElseIf .Style = "Body Heading" Or .Style = "Document Heading" Or _ .Style = "Page Heading" Then .Style = "Heading 1" End If End With Next End With
The savings with Select Case
is the ability to separate multiple options with just a comma rather than repeating the entire condition for each option. As you gain experience writing your own macros, you will run into many situations where If
or Select Case
is the better choice.
VBA uses both symbols (such as &, <, >, =, +, -, /, *) and terms (such as And, Or, and To) for operators, depending on the usage. In all cases, however, operators follow standard mathematical syntax rules. Take a look at a few examples.
When I finish writing a chapter of this book, I need to copy all of the Heading 1 and Heading 2 paragraphs to update the table of contents. To do that, I make a copy of the document, from which I delete any paragraphs that don’t have those two styles applied.
Dim apr as Paragraph For each apr in ActiveDocument.Paragraphs If apr.Style <> "Heading 1" And apr.Style <> "Heading 2" Then apr.Range.Delete End If Next apr
The less than and greater than operators are used together here to mean “is not equal to.” Note that I could also have written the If
portion of that statement as follows:
If Not apr.Style = "Heading 1" And Not apr.Style = "Heading 2" Then
Notice that the use of Not
to mean “anything other than” is repeated for each option meeting the condition.
If, instead, I wanted to delete all paragraphs that match either of those criteria, I would have written the following code:
Dim apr as Paragraph For each apr in ActiveDocument.Paragraphs If apr.Style = "Heading 1" Or apr.Style = "Heading 2" Then apr.Range.Delete End If Next apr
What if I wanted to delete all paragraphs that use Heading 1 or Heading 2 style, but only if they don’t appear in a table?
Dim apr as Paragraph For each apr in ActiveDocument.Paragraphs If (apr.Style = "Heading 1" Or apr.Style = "Heading 2") And _ apr.Range.Information(wdWithinTable) = False Then apr.Range.Delete End If Next apr
In the first line of the If
structure, the space followed by an underscore at the end of the line breaks a single statement of code to a second line. Breaking the line is not required, but is used when the line of code is too wide to read in a single screen.
Notice in the preceding code that the conditions that use the logical operator Or
are grouped in parentheses, with the And
operator outside the parentheses. Just as in a mathematical equation, that phrasing ensures that the condition within the parentheses is evaluated first.
As you’ve seen in examples throughout the primer to this point, an ampersand combines arguments into a text string, and typical arithmetic operators can be used on numeric values as they are in Excel formulas, including +, - ,*, and /. The plus sign can be used in some cases to combine text strings, but when you want to mix different types of variables in a text string, the plus sign can cause a “Type Mismatch” error, because it tries to calculate a result rather than combine the strings. So, using the ampersand to combine arguments into a string is always a good practice.
Notice also throughout these examples that comparison operators can be used either individually or together, such as < to indicate “less than” or <= to mean “less than or equal to.”
See Also Although the operators mentioned in this section are likely to be all that you need, they’re not an exhaustive list of every operator available in VBA. To learn about others, search for the topic Operator Keyword Summary in VBA help.
Although it’s not included in the aforementioned Operator Keyword Summary, the term To can be used to represent a range of values (such as a more efficient alternative to using a greater than and less than range combined), as you’ve already seen in some code examples in this chapter. Consider the following examples, which are individual lines of a code from a For…Next
loop and a Select Case
statement.
For myI = 1 to ActiveDocument.Shapes.Count Case 2, 3 To 10, 14
When creating macros for others to use, you’ll likely need to either give the user information or have the user specify information. Use message boxes to share information and input boxes to collect it.
A message box might simply provide information, or it might require a response, such as Yes, No, Cancel, Abort, Retry, or Ignore.
The MsgBox
command is one of several in VBA that can be used both as a statement and as a function. Use a MsgBox
statement to provide information; use MsgBox
as a function when you need a response from the user.
To create a message box statement, type MsgBox
with the string of text you want the user to see. For example, take a look at the following message box statement and the message box it produces when run in Word, shown in Figure 23-19.
MsgBox "You're an unstoppable VBA genius!"
Figure 23-19. Notice that message boxes and input boxes automatically coordinate with the visual aesthetic of Microsoft Office on their respective platforms.
Even if your message box doesn’t require a reply, however, you might want to get a bit more creative with it. The MsgBox
command includes optional arguments that let you customize the title bar and add an information icon, as shown in Figure 23-20.
MsgBox "You're an unstoppable VBA genius!",vbInformation,"My Message Box"
Figure 23-20. A message box with custom title bar and information icon, shown in Office 2010 (left) and Office 2011 (right).
The intrinsic constant vbInformation
is one of a set of options in the buttons argument that enables you to add both an icon (as you see here) and response buttons. The third argument customizes the title of the message box.
Notice that including a title in Office 2011 reduces the size of the message box body text and places the title within the body area of the message. Also notice that the custom icons are not provided in Office 2011. Instead, the information icon is read as the application icon (Word, in this case).
To use MsgBox
as a function (that is, to require a response from the user), first declare an integer variable for your message box so that you can use the response in the macro, as you see in the following example:
Dim myRes As Integer myRes = Msgbox("Are you an unstoppable VBA genius?", vbQuestion _ + vbYesNo, "My Message Box") If myRes = vbYes Then Msgbox "I knew it!", vbExclamation, "You're a genius!" Else Msgbox "Hang in there.", vbCritical, "It will get easier!" End If
The first message box in the preceding code is shown in Figure 23-21.
Depending upon the user’s response, one of the two message boxes shown in Figure 23-22 is returned.
See Also Both message box and input box functions also include optional arguments for adding context-sensitive help files to those boxes. For additional resources where you can find information on VBA tasks that are not covered in this primer, such as creating custom help files for your VBA projects, see the Getting Help section, later in this chapter.
Input boxes are similar to messages boxes, except that they’re always used as a function because they always require a response. Take a look at the following example:
Dim myInp As String myInp = InputBox("How would you score on a basic VBA exam?", _ "My Input Box", "Perfect") Msgbox myInp & " is pretty good!", vbExclamation, "My Input Box"
The input box from this code sample is shown in Figure 23-23. Notice that the Office 2010 and Office 2011 input boxes are more similar than message boxes. For example, note that the title bar is utilized in Office 2011 message boxes.
The text of the message box shown in Figure 23-23 is referred to as the prompt, the title bar text is the title argument (as in a message box), and the value you see in this image is the default value of “Perfect” specified in the third argument. Note that input boxes also include optional arguments for vertical and horizontal position on the screen (not shown here) for cases where you don’t want the box to automatically appear in the center of the screen.
Because the input box was declared as a string variable, notice that the response is used as part of a text string in a message box, as shown in the preceding code sample and in Figure 23-24.
If, instead, you need to use a response as a numeric value, declare the variable accordingly. In the following example, the input box asks for the number of columns to include in a new table being created by the macro. The variable defined as the input box reply is declared as an integer. (Notice that the input box in this case has only a prompt and a title bar—no default value is set, so the text box within the input box appears blank to the user.)
Dim myInp As Integer myInp = InputBox("How many columns would you like?", "My Input Box") With Selection .Tables.Add Range:=.Range, NumRows:=5, NumColumns:=myInp End With
There is a possible problem, however, with the preceding code sample. If the response is not an integer (including if the user cancels the input box without adding a reply), the macro will end in an error. You can, however, add what’s known as an error handler to correct for any error that may occur. Error handlers are an important part of writing macros effectively.
Companion Content To learn how to work with code errors and create error handlers, see the article “Managing VBA Errors,” available in the Bonus Content folder as part of the online companion content for this book, at http://oreilly.com/catalog/9780735651999. You’ll find an example in that article of an error handler created specifically for the preceding macro.
When you create a solution, such as developing a set of document production macros for yourself or creating a set of macros to help users format a template, you’re likely to have some of the same commands repeat in multiple macros. When those duplicated commands run to more than a few lines of code, it can be helpful to put the duplicated code into its own macro and run it as part of each macro that needs it. That way, you don’t have to write that code out in every macro where you need it.
Running one macro from another is also commonly done when several macros use the same variable definitions. For example, say that you declare the following public variables in the General Declarations section of the module:
Public myName as String, myComp as String, myIn as Integer
If several macros need to use the same values for that information, create a procedure just to store the values of those variables. That entire macro might look something like this:
Public Sub VarDefs() myName = Application.UserName myComp = ActiveDocument.BuiltinDocumentProperties("Company").Value myIn = 1 End Sub
To then use these variable definitions in any macro in the project, simply call the macro that includes the definitions. The statement to call a macro is just the word Call
plus the macro name. If the macro exists in a different module from the macro where you’re calling it, also specify the module name.
For example, to call the preceding macro from a macro in the same module, type the following statement:
Call VarDefs
If the macro from which you want to call VarDefs
is in a different module, the statement would look like the following (assuming that VarDefs
is in a module named myMod
):
Call myMod.VarDefs
Note that, as long as the variables are declared as public, you don’t actually have to specify Public
in the Sub
statement of the preceding macro to make the contents of that procedure available to other macros in the project. However, if you want to allow the contents of that procedure to be shared only by other macros in the same module (such as in cases where macros in a different module might need to share a different set of values for the same variables), use Private Sub <procedurename>()
to start the macro. Keep in mind that private procedures don’t appear in the Macros dialog box available from the Developer tab, so identifying a procedure as private is also a good way to keep it hidden from the user.
When you call one macro from another for the purpose of using variable definitions, make sure the call to the source macro appears prior to where you use those variables in the destination macro.
Your macros might share many types of variables in a given project. The preceding variable example is just intended to point out one place where the Microsoft Office programs may offer you a simpler solution than VBA, depending on your particular needs. For adding document property information to your documents and templates, you can use the built-in Document Property Quick Parts.
See Also For more information about Document Property Quick Parts that have information already bound to content controls, as well as for resources where you can learn about creating custom bound controls, see Chapter 12.
You can add a statement to end the macro under specified conditions or to exit just a part of the macro.
To end execution of a macro, use the term Exit Sub
. For example, say that you want to stop a macro from running if no document is open. That code would look like this:
If Documents.Count = 0 Then Exit Sub End If
Exit Sub
, however, exits the active procedure. If you have one procedure running from another, you might need to end code execution entirely instead of exiting the individual subroutine. In that case, just use the term End
.
If Documents.Count = 0 Then End End If
To exit a loop when a condition is met, use an Exit
statement specifically for the loop type, such as Exit For
or Exit Do
. Following is an example of an Exit For
statement:
Dim ast as Style For each ast in ActiveDocument.Styles If ast.NameLocal = "Sample" Then ast.Delete Exit For End If Next
You can run a macro directly from the Visual Basic Editor or from the Macros dialog box available in the Microsoft Office programs, or you can customize the user interface to add the macro to either the Quick Access Toolbar or the Ribbon (or, in Office 2011, to a toolbar or menu). In Word 2010 or Word 2011, you can also assign a keyboard shortcut to a macro.
To add a macro to the Quick Access Toolbar or the Ribbon in an Office 2010 program, using the Customize Quick Access Toolbar and Customize Ribbon tabs of the Options dialog box in the applicable program.
To add a macro to a toolbar or menu in an Office 2011 program, on the View menu, point to Toolbars, and then click Customize Toolbars And Menus.
To assign a keyboard shortcut to a macro in Word 2010, on the Customize Ribbon tab of the Word Options dialog box, under the heading Keyboard Shortcuts, click Customize. To do this in Word 2011, on the Tools menu, click Customize Keyboard.
You can save keyboard shortcut assignments, Quick Access Toolbar customizations, and Office 2011 menu and toolbar customizations either for the application as a whole or in the individual document or template. When you customize the Ribbon through the options dialog box, you can customize it only for the application as a whole. To customize the Ribbon for an individual document, template, or add-in in Office 2010, you have to use Office Open XML.
See Also For more on Office Open XML, see Chapter 24. Additionally, see the article “Using VBA to Create Add-Ins,” available on the MSDN Office Developer Center at http://msdn.microsoft.com/en-us/library/gg597509.aspx. (This article applies to both Office 2010 and Office 2011. Office 2010 UI customization examples are presented in the article but the downloadable samples for the article also include an Office 2011 UI customization example.)
As you’re writing lengthy macros, or when you’re ready to use your macros, compiling the project is an important step. Compilers are actually used to translate source code to executable code, which isn’t strictly necessary for typical VBA macros. But using the compiler in the Visual Basic Editor is an essential way to help ensure that your code works properly.
To compile a project, just select a module or click into a procedure in the project and then, on the Debug menu, click Compile <Project>. Depending on the size of the VBA project, compiling might be instantaneous or it might take a few moments. If VBA recognizes errors in your code, it will select the code containing the error and display a message box telling you the type of error.
Companion Content Learn about recognizing, fixing, and managing errors in the article “Managing VBA Errors,” available in the Bonus Content folder online at http://oreilly.com/catalog/9780735651999.
In Office 2010 VBA, you can easily search for help using the Type A Question For Help box that appears on the right side of the Visual Basic Editor menu bar. In Office 2011, VBA help takes you to an online index of VBA help topics.
But there are also often faster ways to get to exactly what you need:
In the case of error messages, the Help button in those message boxes takes you directly to a help article on that specific error message. If, however, you need information on an error message any time other than right when it occurs, search for the help topic Trappable Errors. You can then use the Find feature in the help or browser window (Ctrl+F on Windows and Command+F on Mac) to quickly locate the name or number of the particular error you need. The Trappable Errors article lists each error with a hyperlink to its article.
In the case of any object model member, right-click the name of the item where it appears in the code and then click Definition. This opens the Object Browser to the selected item—which might be enough information if you just need, for example, to see the available members of a selected object.
However, in the Object Browser in Office 2010, you can right-click any item and then click Help to open the help topic on that article. Note that some items, such as individual constants, might not have help articles—but articles are available for most members of the active object model.
You can export a module of code (as well as some other types of project elements), which is the equivalent of saving a copy of the file, by right-clicking the module in the Project Explorer pane and then clicking Export. Note that the file name you choose for the export doesn’t need to match the module name. Notice also that VBA modules have the file extension .bas.
To import a module of code, such as the samples available in the online bonus content for this book, right-click the project in Project Explorer and then click Import.
If you export or import modules, remember that some modules refer to code outside the module itself, such as when the project contains a UserForm (dialog box) or when one macro calls another from a different module in the project. Be sure that you’re aware of the project components that need to work together, so that you export or make note of everything you’ll need when you or someone else imports that content later.
See Also For additional resources, such as where you can learn to create and work with UserForms, see the section Working with VBA: Next Steps at the end of this chapter.
Because you can share an entire VBA project by sharing the Word, Excel, or PowerPoint file in which the project is stored, exporting is more often used as backup. This is usually a good idea, because if you lose a document or template, you of course lose any code it contained.
In particular, if you store a module of document production macros, for example, in Normal.dotm, exporting that module periodically for backup is an important safety measure. This is because you might solve some Word performance issues by deleting Normal.dotm and allowing Word to regenerate a new default template, in which case your macros would be lost.
To share an entire project, just compile the project, save the file, and share it as you would any file. Keep in mind that some networks block files that contain macros, so you might want to use a different method for safely sharing the content (such as saving a document or template containing a VBA project to a Windows Live SkyDrive folder or a Microsoft SharePoint library).
Some macro projects need to be saved as particular file types, such as for Excel and PowerPoint add-ins. Also, adding a digital signature to projects can help to avoid systems or programs blocking your macros.
See Also Learn about using VBA to create add-ins and signing your code in the MSDN Office Developer Center article “Using VBA to Create Add-Ins,” at http://msdn.microsoft.com/en-us/library/gg597509.aspx.
You can also protect your code when sharing projects—such as when you want others to be able to use the macros, but not to be able to see or copy your source code. To do this, select the project in Project Explorer. Then, on the Tools menu, click <Project> Properties.
In the <Project> Properties dialog box, you can rename the project (following VBA naming conventions), which does not affect the file name of the document, template, or add-in where the project resides. You can also click the Protection tab to require a password to view the code. For this feature to work, you must enable the Lock Project For Viewing option and provide a password. When you do, double-clicking the project in Project Explorer will display a box where you can type the password. Without the correct password, the macros can still be run from the user interface, but their code can’t be viewed. Note that, once you add a password, the password protection starts the next time the project is opened.
Once you’ve mastered the basics in this primer, you’re likely to find more complex VBA to be quite easy. And there are many online resources to help you progress.
The MSDN Office Developer Center (http://msdn.microsoft.com/office) is a fantastic resource for all things related to automating Microsoft Office. The majority of content on this site is for managed code (Microsoft Visual Studio) development (the platform often used by professional Microsoft Office developers), but far from all of it. You can find a growing number of resources on VBA as well as a volume of information on Office Open XML (which is addressed in Chapter 24).
The Office Developer Center also has a VBA-specific site that’s a fantastic online home base for learning about VBA. And it has one of my all-time favorite friendly URLs: http://iheartmacros.com.
In addition, when you don’t find the information you need in VBA help, search the MSDN library. The library’s resources are pretty amazing—I can’t tell you how much I’ve learned there: http://msdn.microsoft.com/library.
But in addition to general resources, there’s also more VBA topic-specific content that I’d like to point out. The online bonus content for this book includes a couple of VBA articles, and there are also a few articles available on the Office Developer Center that might be particularly handy for next steps with VBA.
The list of four articles that follows was written for Office 2007 but also applies to Office 2010 and Office 2011. In the additional resources at the end of each article, find a link to a related video walk-through of tasks covered in it.
The Immediate window in the Visual Basic Editor (discussed in the earlier sidebar Do More Than You Might Imagine with One Line of Code is one of my favorite tools, and by far one of the most valuable tools for using VBA to troubleshoot document formatting. Learn more about the Immediate window here: http://msdn.microsoft.com/en-us/library/dd535470.aspx.
Get tips on using VBA specifically to troubleshoot documents here: http://msdn.microsoft.com/en-us/library/dd630112.aspx.
Learn about controlling built-in Microsoft Office commands using VBA (including an introduction to using events) here: http://msdn.microsoft.com/en-us/library/dd627337.aspx.
See examples of how to use some of what you learned in this primer to format long documents more quickly and easily here: http://msdn.microsoft.com/en-us/library/dd554917.aspx.
Companion Content Find articles on how to create and use UserForms (dialog boxes) in VBA and how to manage VBA errors, as well as a list of all links provided in this chapter and others, in the online Bonus Content folder available online as part of the companion content for this book, at http://oreilly.com/catalog/9780735651999.
Before you go, however, the next (and final) chapter in this book provides a similar primer on the basics of using the Office Open XML Formats to edit documents and create custom content.
18.188.198.94