Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 99 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
99
Dung lượng
809,52 KB
Nội dung
258 Part III ✦ Understanding Visual Basic for Applications Why Create Custom Functions? You are undoubtedly familiar with Excel’s worksheet functions; even novices know how to use the most common worksheet functions, such as SUM, AVERAGE, and IF. By my count, Excel contains more than 300 predefined worksheet functions, plus additional functions available through the Analysis Toolpak add-in. If that’s not enough, however, you can create custom functions by using VBA. With all the functions available in Excel and VBA, you may wonder why you would ever need to create new functions. The answer: to simplify your work. With a bit of planning, custom functions are very useful in worksheet formulas and VBA procedures. Often, for example, you can create a custom function that can significantly shorten your formulas. And shorter formulas are more readable and easier to work with. I should also point out, however, that custom functions used in your formulas are usually much slower than built-in functions. As you create applications, you may notice that some procedures repeat certain calculations. In such a case, consider creating a custom function that performs the calculation. Then you can simply call the function from your procedure. A custom function thus can eliminate the need for duplicated code, reducing errors. Co-workers often can benefit from your specialized functions. And some may be willing to pay you for custom functions that save them time and work. Although many cringe at the thought of creating custom worksheet functions, the process is not difficult. In fact, I enjoy creating custom functions. I especially like how my custom functions appear in the Paste Function dialog box along with Excel’s built-in functions, as if I’m reengineering the software in some way. In this chapter, I tell you what you need to know to start creating custom functions, and I provide lots of examples. An Introductory Example Without further ado, here’s an example of a VBA Function procedure. A custom function The following is a custom function defined in a VBA module. This function, named Reverse, uses a single argument. The function reverses the characters in its argu- ment (so that it reads backwards), and returns the result as a string. 4799-2 ch10.F 6/11/01 9:31 AM Page 258 259 Chapter 10 ✦ Creating Function Procedures Function Reverse(InString) As String ‘ Returns its argument, reversed Dim i as Integer, StringLength as Integer Reverse = “” StringLength = Len(InString) For i = StringLength To 1 Step -1 Reverse = Reverse & Mid(InString, i, 1) Next i End Function I explain how this function works later, in the “Analyzing the custom function” section. When you create custom functions that will be used in a worksheet formula, make sure that the code resides in a normal VBA module. If you place your custom func- tions in a code module for a Sheet or ThisWorkbook, they will not work in your formulas. Using the function in a worksheet When you enter a formula that uses the Reverse function, Excel executes the code to get the value. Here’s an example of how you would use the function in a formula: =Reverse(A1) See Figure 10-1 for examples of this function in action. The formulas are in column B, and they use the text in column A as their argument. As you can see, it returns its single argument, but its characters are in reverse order. Actually, the function works pretty much like any built-in worksheet function. You can insert it in a formula by using the Insert ➪ Function command or the Insert Function button (in the Insert Function dialog box, custom functions are located, by default, in the User Defined category). Figure 10-1: Using a custom function in a worksheet formula Caution 4799-2 ch10.F 6/11/01 9:31 AM Page 259 260 Part III ✦ Understanding Visual Basic for Applications You can also nest custom functions and combine them with other elements in your formulas. For example, the following (useless) formula uses the Reverse function twice. The result is the original string: =Reverse(Reverse(A1)) Using the function in a VBA procedure The following VBA procedure, which is defined in the same module as the custom Reverse function, first displays an input box to solicit some text from the user. Then the procedure uses VBA’s built-in MsgBox function to display the user input after it’s processed by the Reverse function (see Figure 10-2). The original input appears as the caption in the message box. Sub ReverseIt() Dim UserInput as String UserInput = InputBox(“Enter some text:”) MsgBox Reverse(UserInput), , UserInput End Sub In the example shown in Figure 10-2, the string entered in response to the InputBox function was Excel Power Programming With VBA. The MsgBox function displays the reversed text. Figure 10-2: Using a custom function in a VBA procedure Analyzing the custom function Function procedures can be as complex as you need. Most of the time, they are more complex and much more useful than this sample procedure. Nonetheless, an analysis of this example may help you understand what is happening. Here’s the code, again: Function Reverse(InString) As String ‘ Returns its argument, reversed Dim i as Integer, StringLength as Integer Reverse = “” StringLength = Len(InString) For i = StringLength To 1 Step -1 Reverse = Reverse & Mid(InString, i, 1) Next i End Function 4799-2 ch10.F 6/11/01 9:31 AM Page 260 261 Chapter 10 ✦ Creating Function Procedures Notice that the procedure starts with the keyword Function, rather than Sub, fol- lowed by the name of the function ( Reverse). This custom function uses only one argument ( InString), enclosed in parentheses. As String defines the data type of the function’s return value. (Excel uses the variant data type if none is specified.) The second line is simply a comment (optional) that describes what the function does. This is followed by a Dim statement for the two variables (i and StringLength) used in the procedure. Then the procedure initializes the result as an empty string. Note that I use the function’s name as a variable here. When a function ends, it always returns the current value of the variable that corresponds to the function’s name. Next, VBA’s Len function determines the length of the input string and assigns this value to the StringLength variable. The next three instructions make up a For-Next loop. The procedure loops through each character in the input (backwards) and builds the string. Notice that the Step value in the For-Next loop is a negative number, causing the looping to proceed in reverse. The instruction within the loop uses VBA’s Mid function to return a single character from the input string. When the loop is finished, Reverse consists of the input string, with the characters rearranged in reverse order. This string is the value that the function returns. The procedure ends with an End Function statement. What Custom Worksheet Functions Can’t Do As you develop custom functions, it’s important to understand a key distinction between functions that you call from other VBA procedures and functions that you use in worksheet formulas. Function procedures used in worksheet formulas must be “passive.” For example, code within a Function procedure cannot manipulate ranges or change things on the work- sheet. An example may make this clear. You may be tempted to write a custom worksheet function that changes a cell’s formatting. For example, it might be useful to have a formula that uses a custom function to change the color of text in a cell based on the cell’s value. Try as you might, however, such a function is impossible to write. No matter what you do, the function will always return an error. Remember, a function simply returns a value. It cannot perform actions with objects. 4799-2 ch10.F 6/11/01 9:31 AM Page 261 262 Part III ✦ Understanding Visual Basic for Applications Function Procedures A custom Function procedure has a lot in common with a Sub procedure. (For more information on Sub procedures, see Chapter 9.) Declaring a function The syntax for declaring a function is as follows: [Public | Private][Static] Function name ([arglist])[As type] [instructions] [name = expression] [Exit Function] [instructions] [name = expression] End Function In which: Public (Optional) Indicates that the Function procedure is accessible to all other procedures in all other modules in all active Excel VBA projects. Private (Optional) Indicates that the Function procedure is accessible only to other procedures in the same module. Static (Optional) Indicates that the values of variables declared in the Function procedure are preserved between calls. Function (Required) Is the keyword that indicates the beginning of a procedure that returns a value or other data. name (Required) Represents any valid Function procedure name, which must follow the same rules as a variable name. When the function finishes, the result is assigned to its own name. arglist (Optional) Represents a list of one or more variables that represent arguments passed to the Function procedure. The arguments are enclosed in parentheses. Use a comma to separate pairs of arguments. type (Optional) Is the data type returned by the Function procedure. instructions (Optional) Are any number of valid VBA instructions. Exit Function (Optional) Is a statement that forces an immediate exit from the Function procedure prior to its completion. End Function (Required) Is a keyword that indicates the end of the Function procedure. 4799-2 ch10.F 6/11/01 9:31 AM Page 262 263 Chapter 10 ✦ Creating Function Procedures The main thing to remember about a custom function written in VBA is that a value is always assigned to its name a minimum of one time, generally when it has com- pleted execution. To create a custom function, start by inserting a VBA module. (Or you can use an existing module.) Enter the keyword Function, followed by the function’s name and a list of its arguments (if any) in parentheses. You can also declare the data type of the return value by using the As keyword (this is optional, but recom- mended). Insert the VBA code that performs the work, and make sure that the appropriate value is assigned to the term corresponding to the function’s name at least once within the body of the Function procedure. End the function with an End Function statement. Function names must adhere to the same rules for variable names. If you plan to use your custom function in a worksheet formula, make sure the name is not in the form of a cell address (for example, a function named J21 won’t work in a formula). And, avoid using function names that correspond to Excel’s built-in function names. If there is a function name conflict, Excel will always use its built-in function. A function’s scope In Chapter 9, I discussed the concept of a procedure’s scope (public or private). The same discussion applies to functions: A function’s scope determines whether it can be called by procedures in other modules or in worksheets. Here are a few things to keep in mind about a function’s scope: ✦ If you don’t declare a function’s scope, its default is public. ✦ Functions declared As Private do not appear in Excel’s Paste Function dialog box. Therefore, when you create a function that should be used only in a VBA procedure, you should declare it private so that users don’t try to use it in a formula. ✦ If your VBA code needs to call a function that’s defined in another workbook, set up a reference to the other workbook by using VBE’s Tools➪ References command. Executing Function procedures Although you can execute a Sub procedure in many ways, you can execute a Function procedure in only two ways: ✦ Call it from another procedure ✦ Use it in a worksheet formula 4799-2 ch10.F 6/11/01 9:31 AM Page 263 264 Part III ✦ Understanding Visual Basic for Applications From a procedure You can call custom functions from a procedure the same way you call built-in func- tions. For example, after you define a function called SumArray, you can enter a statement like the following: Total = SumArray(MyArray) This statement executes the SumArray function with MyArray as its argument, returns the function’s result, and assigns it to the Total variable. You also can use the Run method of the Application object. Here’s an example: Total = Application.Run (“SumArray”, “MyArray”) The first argument for the Run method is the function name. Subsequent arguments represent the argument(s) for the function. The arguments for the Run method can be literal strings (as shown above), numbers, or variables. In a worksheet formula Using custom functions in a worksheet formula is like using built-in functions, except that you must ensure that Excel can locate the Function procedure. If the Function procedure is in the same workbook, you don’t have to do anything special. If it’s in a different workbook, you may have to tell Excel where to find it. You can do so in three ways: ✦ Precede the function’s name with a file reference. For example, if you want to use a function called CountNames that’s defined in an open workbook named Myfuncs.xls, you can use the following reference: =Myfuncs.xls!CountNames(A1:A1000) If you insert the function with the Paste Function dialog box, the workbook reference is inserted automatically. ✦ Set up a reference to the workbook. You do so with the VBE’s Tools ➪ References command. If the function is defined in a referenced workbook, you don’t need to use the worksheet name. Even when the dependent workbook is assigned as a reference, the Paste Function dialog box continues to insert the workbook refer- ence (although it’s not necessary). ✦ Create an add-in. When you create an add-in from a workbook that has Function procedures, you don’t need to use the file reference when you use one of the functions in a formula. The add-in must be installed, however. I discuss add-ins in Chapter 21. 4799-2 ch10.F 6/11/01 9:31 AM Page 264 265 Chapter 10 ✦ Creating Function Procedures You’ll notice that, unlike Sub procedures, your Function procedures do not appear in the Macro dialog box when you issue the Tools ➪ Macro ➪ Macros command. In addition, you can’t choose a function when you issue the VBE’s Run ➪ Sub/ UserForm command (or press F5) if the cursor is located in a Function procedure (you get the Macro dialog box that lets you choose a macro to run). As a result, you need to do a bit of extra up-front work to test your functions as you’re developing them. One approach is to set up a simple procedure that calls the function. If the function is designed to be used in worksheet formulas, you’ll want to enter a simple formula to test it. Reinventing the Wheel Most of Excel’s built-in functions are impossible to create in VBA. However, some can be duplicated. Just for fun, I wrote my own version of Excel’s UPPER function (which converts a string to all uppercase) and named it UpCase: Function UpCase(InString As String) As String ‘ Converts its argument to all uppercase. Dim StringLength As Integer Dim i As Integer Dim ASCIIVal As Integer Dim CharVal As Integer StringLength = Len(InString) UpCase = InString For i = 1 To StringLength ASCIIVal = Asc(Mid(InString, i, 1)) CharVal = 0 If ASCIIVal >= 97 And ASCIIVal <= 122 Then CharVal = -32 Mid(UpCase, i, 1) = Chr(ASCIIVal + CharVal) End If Next i End Function I was curious to see how the custom function differed from the built-in function, so I cre- ated a worksheet that called the function 10,000 times, using an argument that was 26 characters long. The worksheet took 13 seconds to calculate. I then substituted Excel’s UPPER function and ran the test again. The recalculation time was virtually instantaneous. I don’t claim that my UpCase function is the optimal algorithm for this task, but it’s safe to say that a custom function will never match the speed of Excel’s built-in functions. 4799-2 ch10.F 6/11/01 9:31 AM Page 265 266 Part III ✦ Understanding Visual Basic for Applications Function Arguments Keep in mind the following points about Function procedure arguments: ✦ Arguments can be variables (including arrays), constants, literals, or expressions. ✦ Some functions do not have arguments. ✦ Some functions have a fixed number of required arguments (from 1 to 60). ✦ Some functions have a combination of required and optional arguments. If your formula uses a custom worksheet function and it returns #VALUE!, there is an error in your function. The error could be caused by logical errors in your code, by passing incorrect arguments to the function, or by performing an illegal action (such as attempting to change the formatting of a cell). See “Debugging Func- tions” later in this chapter. Function Examples In this section, I present a series of examples, demonstrating how to use argu- ments effectively with functions. By the way, this discussion also applies to Sub procedures. All the function examples in this section are available on the companion CD-ROM. A function with no argument Like Sub procedures, Function procedures need not have arguments. Excel, for example, has a few built-in functions that don’t use arguments, including RAND(), TODAY(), and NOW(). You can create similar functions. Here’s a simple example of a function that doesn’t use an argument. The following function returns the UserName property of the Application object. This name appears in the Options dialog box (General tab) and is stored in the Windows Registry. Function User() ‘ Returns the name of the current user User = Application.UserName End Function On the CD-ROM Note 4799-2 ch10.F 6/11/01 9:31 AM Page 266 267 Chapter 10 ✦ Creating Function Procedures When you enter the following formula, the cell returns the name of the current user (assuming that it’s listed properly in the Registry): =User() When you use a function with no arguments in a worksheet formula, you must include a set of empty parentheses. This requirement is not necessary if you call the function in a VBA procedure, although including the empty parentheses does make it clear that you’re calling a function. To use this function in another procedure, you must assign it to a variable, use it in an expression, or use it as an argument for another function. The following example calls the User function and uses the return value as an argu- ment for the MsgBox statement. The concatenation operator (&) joins the literal string with the result of the User function. Sub ShowUser() MsgBox “Your name is “ & User() End Sub Another function with no argument I used to use Excel’s RAND() function to quickly fill a range of cells with values. But I didn’t like the fact that the random numbers change whenever the worksheet is recalculated. So I usually had to convert the formulas to values by using the Edit ➪ Paste Special command (with the Values option). Then I realized that I could create a custom function that returned random numbers that didn’t change. I used VBA’s built-in Rnd function, which returns a random num- ber between 0 and 1. The custom function is as follows: Function StaticRand() ‘ Returns a random number that doesn’t ‘ change when recalculated StaticRand = Rnd() End Function If you want to generate a series of random integers between 0 and 1000, you can use a formula such as this: =INT(StaticRand()*1000) The values produced by this formula never change, unlike those created by the built-in RAND() function. Note 4799-2 ch10.F 6/11/01 9:31 AM Page 267 [...]... calls For example, if you develop an application using Excel 97 or later that uses API calls, the application will not run with Excel 5 — even if you save the workbook in the Excel 5 format — because Excel 5 is a 16-bit application Excel 97 and later versions are 32-bit applications Excel 2002 is a 32-bit application (and uses 32-bit API calls) and Excel 5 is a 16-bit application Refer to Chapter 26 for... I discuss add-ins in Chapter 21 Using the Windows API VBA can borrow methods from other files that have nothing to do with Excel or VBA — for example, the DLL (Dynamic Link Library) files that Windows and other software use As a result, you can do things with VBA that would otherwise be outside the language’s scope The Windows API (Application Programming Interface) is a set of functions available... tables, events, UserForms, and so on ✦ ✦ ✦ ✦ In This Chapter Examples of using VBA to work with ranges Examples of using VBA to work with workbooks and sheets Custom functions for use in your VBA procedures and in worksheet formulas Examples of miscellaneous VBA tricks and techniques Examples of using Windows API functions ✦ ✦ ✦ ✦ 47 99-2 ch11.F 292 6/11/01 9:31 AM Page 292 Part III ✦ Understanding Visual... use custom VBA functions These functions can be used in worksheet formulas and in other VBA procedures I also described how to call Windows API functions The next chapter contains many examples that demonstrate the techniques discussed in this and previous chapters ✦ ✦ ✦ 47 99-2 ch11.F 6/11/01 9:31 AM Page 291 11 C H A P T E R VBA Programming Examples and Techniques I believe that learning programming. .. step) New Feature In versions prior to Excel 2002, the Insert Function dialog box was known as the Paste Function dialog box This dialog box is enhanced in Excel 2002, and has a new look, plus the ability to search for a function by keyword Unfortunately, this search feature cannot be used to locate custom functions created in VBA Specifying a function category Oddly, Excel does not provide a direct way... Applications A function that returns a VBA array VBA includes a useful function called Array The Array function returns a variant that contains an array (that is, multiple values) If you’re familiar with array formulas in Excel, you’ll have a head start understanding VBA s Array function You enter an array formula into a cell by pressing Ctrl+Shift+Enter Excel inserts brackets around the formula to indicate... Sales * Tier3 Case Is >= 40 000: Commission = Sales * Tier4 End Select End Function After you enter this function in a VBA module, you can use it in a worksheet formula or call the function from other VBA procedures Entering the following formula into a cell produces a result of 3,000 (the amount, 25,000, qualifies for a commission rate of 12 percent): =Commission(25000) 269 47 99-2 ch10.F 270 6/11/01... this chapter, I pick up the pace and present examples that solve practical problems while furthering your knowledge of VBA I’ve categorized this chapter’s examples into six groups: ✦ Working with ranges ✦ Working with workbooks and sheets ✦ VBA techniques ✦ Functions useful in your VBA procedures ✦ Functions you can use in worksheet formulas ✦ Windows API calls CrossReference Subsequent chapters in... along with a default value All the following formulas are valid, and the first two have the same effect: =Draw(A1:A100) =Draw(A1:A100,False) =Draw(A1:A100,True) This function might be useful for choosing lottery numbers, picking a winner from a list of names, and so on 273 47 99-2 ch10.F 2 74 6/11/01 9:31 AM Page 2 74 Part III ✦ Understanding Visual Basic for Applications A function that returns a VBA array... combinations): Ctrl, Shift, Alt 289 47 99-2 ch10.F 290 6/11/01 9:31 AM Page 290 Part III ✦ Understanding Visual Basic for Applications Learning more about API functions Working with the Windows API functions can be tricky Many programming reference books list the declarations for common API calls and often provide examples Usually, you can simply copy the declarations and use the functions without really understanding . response to the InputBox function was Excel Power Programming With VBA. The MsgBox function displays the reversed text. Figure 10-2: Using a custom function in a VBA procedure Analyzing the custom. functions by using VBA. With all the functions available in Excel and VBA, you may wonder why you would ever need to create new functions. The answer: to simplify your work. With a bit of planning,. Is >= 40 000: Commission = Sales * Tier4 End Select End Function After you enter this function in a VBA module, you can use it in a worksheet for- mula or call the function from other VBA procedures. Entering