This code produces the following results in the Immediate window:5100 105 The “W” Hotel, New York City You can use the Debug.Printstatement within any procedure to display results of cal
Trang 1In addition to displaying the value of variables, you can also execute VBA commands in the Immediatewindow Just eliminate the ?character and type the entire command, and then press Enter Typing msg-box(“Tall or Grande?”)and pressing Enter displays the message shown in Figure 4-5.
Figure 4-5
You can even perform calculations in the Immediate window such as:
intTotalEmployees = intTempEmployees + intFullTimeEmployees
The Immediate window is also a powerful debugging tool for your applications For more informationabout the Immediate window, see Chapter 8
Using the Immediate window along with other aspects of the VBA Editor detailed in this chapter, such
as breakpoints and stepping through code, is the most generally accepted method of debugging your code However, there are other options One method that is often used by beginning developers is to place message box code throughout the code to test the values of selected variables or calculations.
Although there is nothing technically wrong with this method, it can be messy and cumbersome After all, when you’re done debugging the code, you still need to comment out or remove all of the message box calls That can be a lot of unnecessary work.
The Debug.Print Statement
As you already know, the ?character is short for Debug.Print, and you’ve seen how easy it is to useboth commands directly in the Immediate window That’s not the only place you can use Debug.Printstatements, The following code illustrates how Debug.Printcan be used within a module, so you canimagine how it can be helpful for testing and debugging
Sub FunWithStringsAndNumbers()Dim strBikes As String
Dim strCost As StringDim strCustomerName As StringDim intBikes As IntegerDim curCost As CurrencystrBikes = “5”
strCost = “100”
strCustomerName = “The “”W”“ Hotel, New York City”
intBikes = 5curCost = 100Debug.Print strBikes + strCostDebug.Print intBikes + curCostDebug.Print strCustomerNameEnd Sub
Trang 2This code produces the following results in the Immediate window:
5100
105
The “W” Hotel, New York City
You can use the Debug.Printstatement within any procedure to display results of calculations or ues of variables in the Immediate window That’s a quick way to confirm that your code is achieving thedesired results
val-The Debug.Assert Statement
You can just as easily type Debug.Assertin the Immediate window This option conditionally suspendsexecution of code at the line where Debug.Assertappears For example, the following code uses theDebug.Assertstatement to stop code execution when a specific condition is met:
Option Compare Database
Private blnUnderBudget As Boolean
Const curBudget = 1000
Private Sub GoShopping()
Dim intSuits As Integer
Dim curSuitPrice As Currency
Dim curTotalPrice As Currency
Dim i as Integer
curSuitPrice = 100
intSuits = InputBox(“Enter the desired number of suits”, “Suits”)
For i=1To intSuits
curTotalPrice = curTotalPrice + curSuitPrice
If curTotalPrice > curBudget ThenblnUnderBudget = FalseElse
blnUnderBudget = TrueEnd If
Debug.Assert blnUnderBudgetNext
End Sub
The code breaks every time you go over budget on your shopping trip You can use this statement whentesting for specific conditions within your code Although Debug.Assertis a good debugging tool, youprobably won’t ever use it in live code because it’s a rather abrupt way to stop an application The userwould get no warning and because the code stops, you do not get to provide him with a friendly mes-sage or explanation
Breakpoints
Breakpoints are simply places in your code that pause execution of code For example, to check the value
of a variable curTotalCostmidway through the following procedure, you’d need to use the
Debug.Printstatement (as in the following code) or set a breakpoint
Trang 3Sub HowMuchCanWeSpend()Dim curTotalPrice As CurrencyDim curUnitPrice As CurrencyDim intNumSocks As IntegerDim i As Integer
curUnitPrice = 3.5intNumSocks = InputBox( _
“Please enter the number of pairs of socks youwant.”, _
“Pairs of Socks”)For i=1 To intNumSockscurTotalPrice = curTotalPrice + curUnitPriceNext
Debug.Print curTotalPriceEnd Sub
This code prints in the Immediate window the amount you’ll spend for the total sock purchase That’sgreat, but what if you want to see how your total expense is adding up as you go? You can certainly add
a Debug.Printstatement within the For Nextloop, but you can also set a breakpoint anywhere inthe procedure Once the breakpoint is reached, you can use the Immediate window to check the value ofyour variables You can set a breakpoint on any line of code except for Dimstatements and comments.The simplest way to set a breakpoint is to click in the left margin of the Code window A brick-coloreddot appears in the margin and the corresponding line of code is highlighted To clear a breakpoint, clickthe left margin again in the same spot You can also set and clear breakpoints by placing your cursor inthe desired line of code and selecting Debug➪ Toggle Breakpoint or pressing F9 When you run thecode, every time the breakpoint is reached, code execution stops and VBA waits for you to decide what
to do next You can choose from the following options:
❑ Check the value of variables in the Immediate window When your code reaches a breakpoint,the value of all variables is retained You can check the value of any variable by using theDebug.Printstatement or the ?character within the Immediate window
❑ Use your mouse to hover over any variable in the current procedure The value of the variable isdisplayed close to the mouse cursor
❑ Press F5 or select Run➪ Continue to continue code execution Execution proceeds until the nextbreakpoint or the end of the procedure
When VBA encounters a breakpoint, it pauses execution immediately before the line of code is executed The line of code that contains the breakpoint is not executed unless or until you choose to step through the code using the F8 key.
Stepping Through Code
In most cases, you design code to run with little or no user intervention However, when you’re testingcode, sometimes it is helpful to do more than insert a couple of breakpoints or include some
Debug.Printstatements If you’re running code with several variable changes or some intricate ing, it can sometimes be helpful to step through the code line by line Doing this allows you to watch thevalue of variables after each line of code is executed This can help you pinpoint any errors or mistakes
loop-in the logic of the code
Trang 4To step through your code, place the cursor at the point that you want to initiate the process and pressF8 to begin the procedure (you can also press F8 after the code has entered break mode to step throughthe remaining code) When you press F8 to begin code execution, the name of the sub or function ishighlighted in yellow Subsequent presses of the F8 key move execution from line to line, highlightingthe next executable line in yellow Comment lines and Dimstatements are skipped when steppingthrough code As you press F8, the highlighted line is executed.
Stepping through code is an important tool so it is worth reiterating how the process works The first
instance of F8 highlights the next executable code; the subsequent instance of F8 executes the
high-lighted code If nothing is highhigh-lighted, F8 highlights code; if something is highhigh-lighted, F8 runs it.
If the current procedure calls another sub or function, F8 will also execute the called procedure line byline If you’re confident that the called procedure doesn’t contain any errors, you can execute the entire
called procedure and then return to line-by-line execution of the calling procedure This is called stepping over the procedure, and it is done by pressing Shift+F8 Stepping over the called procedure executes the
entire procedure and then returns to the calling procedure, to proceed with code execution one step at a
time If you’re within a called procedure, you can press Ctrl+Shift+F8 to step out of the current
proce-dure What’s the difference between stepping over and stepping out of the procedure? If you’re already
in the called procedure, the two are exactly the same But here’s an example that illustrates the differenceand gives you some practice with code Assume you’re stepping through the following code (which is inthe Chapter 4 download material):
Option Compare Database
Private blnUnderBudget As Boolean
Const curBudget = 1000
Private Sub GoShopping()
Dim intSuits As Integer
Dim curSuitPrice As Currency
Dim curTotalPrice As Currency
curSuitPrice = 100
intSuits = InputBox(“Enter the desired number of suits”, “Suits”)
For i=1To intSuits
curTotalPrice = curTotalPrice + curSuitPrice
If curTotalPrice > curBudget ThenblnUnderBudget = FalseElse
blnUnderBudget = TrueEnd If
Next
If blnUnderBudget = False Then
OverBudgetEnd If
End Sub
Private Sub OverBudget()
Debug.Print “You’ve gone over budget.”
Debug.Print “You need to work some overtime.”
Debug.Print “Remember to pay your taxes.”
End Sub
Trang 5Use the F8 key to step through the code until you reach the last If Thenloop (If blnUnderBudget =False Then) When the OverBudgetline is highlighted in yellow (meaning it hasn’t yet been executed),stepping over the OverBudgetprocedure returns execution to the line after the OverBudgetcall (in thiscase the End Ifline) If you step out of the procedure, the OverBudgetprocedure runs, and your codereturns to the GoShoppingprocedure and completes the procedure If, however, you use the F8 key tostep through your code until you reach the first line of the OverBudgetprocedure, stepping out of theprocedure returns you to the line after the OverBudgetcall (the End Ifline) Use the following table as
a cheat sheet and create some simple procedures to test the various debugging techniques shown in thischapter
Debugging Technique Description Keyboard Shortcut
Call StackThe Call Stack dialog box displays a list of the current active procedure(s) when you are stepping throughcode An active procedure is one that is started but not completed You can access the Call Stack dialogbox in several ways, including from the menu bar (View the Call Stack) or by pressing Ctrl+L Because thecall stack is available only in break mode, access to the call stack is often grayed out (disabled)
The Call Stack dialog box is not a window and therefore cannot be left open when stepping through code It is opened and closed at each active procedure.
You gain the most benefit from the Call Stack dialog box when one procedure is calling another or if you have nested procedures, whether they are in the same module or being called by other modules Ifanother procedure is called from the first procedure, the dialog box displays the new procedure at thetop of the list with the original (calling) procedure under it, thus stacking them Figure 4-6 illustrates thisstacking process OverBudgetwas called by GoShopping, so OverBudgetis listed first, and it is high-lighted because it is the procedure being run Once a procedure is finished, it is removed from the stack
In this case, after OverBudgetis run, GoShoppingwill be the only procedure in the stack
VBA executes the remainder of the currentprocedure If executed within the secondprocedure, the entire second procedure isexecuted and execution returns to first pro-cedure on the line following the line thatcalled the second procedure
Executes code one line at a time within thecurrent procedure If a second procedure iscalled from within the first, the entire sec-ond procedure is executed at once
Executes the next line of code in your cedure (highlights line in yellow)
Trang 6pro-Figure 4-6
When stepping through multiple procedures from different modules, or even from the same module, itcan be a little confusing as to where a particular procedure is being called To help find the start of the anyactive procedure in the call stack, highlight the active (top) procedure in the list and either double-clickthe item or click the Show button In the current example, the call stack was opened when OverBudgetwas called, so two procedures are listed To find out what line called OverBudget, you can double-click
on GoShopping, the calling procedure This puts a green pointer at the line in GoShoppingthat calledOverBudget Figure 4-7 shows OverBudgetstill highlighted in yellow, because that’s the current point
in stepping through the code, and the green pointer at the call to OverBudget
Figure 4-7
Trang 7As you might imagine, the call stack is helpful when you are working with multiple procedures and ing to determine where errant data may be originating It is also a handy tool when working with some-one else’s application or even modules
try-Run to CursorMany times when you’re executing code, you don’t want to run every line of code line by line, but exe-cuting the entire procedure at once doesn’t help you isolate the problem And it is very tedious to exe-cute every line of the loop each time a long loop needs to run For example, consider the following code:Sub CoffeeTime()
Dim curLatteAllowance As CurrencyDim curLattePrice As CurrencyDim intNumLattes As IntegerDim curTotalExpenses As CurrencycurLattePrice = 3.5
curLatteAllowance = InputBox( _
“Enter the amount of money you have for lattes.”, _
“Latte Allowance”)While curTotalExpenses < curLatteAllowanceintNumLattes = intNumLattes + 1curTotalExpenses = curTotalExpenses + curLattePriceWend
Debug.Print intNumLattesMsgBox “You can purchase “ & intNumLattes & “ lattes.”, _vbOkOnly, “Total Lattes”
Locals WindowSometimes it can be utterly mind-numbing to test the value of every variable when your code entersbreak mode If you’re stepping through code and need to test the value of seven different variables everystep of the way, that’s a lot of Debug.Printstatements to keep track of in the Immediate window Youcan use the Locals window to display all the variables in a procedure and their values You can watchthe variable values change as you step through the code To display the Locals window, select View➪Locals Window Figure 4-8 shows the Locals window while stepping through a procedure
As you step through the procedure, the Locals window shows you the up-to-date values of all variables.The Locals window is not emptied until the last line of code has been executed In this case, you’d see amessage box stating, “You can purchase 100 lattes.”
Trang 8Figure 4-8
Watch Window
The last debugging tool you’ll examine in this chapter is the Watch window, which enables you to watch
a variable within your procedure When the value of the variable changes or when the variable is True,your code enters break mode To open the Watch window, select View➪ Watch Window
To see how the Watch window works, use WatchGoShoppingSuits, a modified version of the GoShoppingule Recall that it uses a Boolean expression and message box to let you know if you’re over budget Add a watch
mod-on the blnOverBudget.Startby right-clicking in the Watch window and choosing Add Watch The Add Watchdialog box opens (see Figure 4-9)
Enter blnOverBudgetin the Expression text box In the Watch Type, the default is to Watch
Expression, although you could choose Break When Value is True, or Break When Value Changes For this example, choose Break When Value Is True, and then click OK to save your watch When yourun the SteppingThroughCodeGoShopping2procedure, the procedure enters break mode when thevalue of blnOverBudgetbecomes true As soon as the loop executes for the eleventh time, the watchexpression is triggered and the code enters break mode
If you choose to simply watch the expression (rather than break), the Watch window behaves almostexactly like the Locals window except that only watched variables are shown
Trang 9Figure 4-9
If you have a rather long loop to execute and you no longer need your watch, you can delete it while your code is in break mode Simply right-click the watch and select Delete Watch You can then press F5
to continue code execution.
Option Compare DatabasePrivate blnOverBudget As BooleanConst curBudget = 1000
Private Sub GoShoppingSuits()Dim intSuits As IntegerDim curSuitPrice As CurrencyDim curTotalPrice As CurrencycurSuitPrice = 100
intSuits = InputBox(“Enter the desired number of suits”, “Suits”)For i=1 To intSuits
curTotalPrice = curTotalPrice + curSuitPrice
If curTotalPrice > curBudget ThenblnOverBudget = True
ElseblnOverBudget = FalseEnd If
Trang 10If blnOverBudget = True Then
Msgbox “You’re over budget!”, vbExclamation, “Over Budget”
dis-by pressing the F8 key and stepping through that line of code If you realize that the problem is severallines before the current location, you can make the correction and easily restart the code from a differentlocation Just click on the original arrow (pointer) and drag it to the line where you want to start execut-ing the code
Be aware that depending on what code was executed, you may not get valid results, particularly if it isdependent on earlier code or values So if you think you’ve corrected the problem but it still isn’t dis-playing the expected values, it would be prudent to rerun the entire module or function
Also, code changes during execution may not always be saved when the program ends Although all thescenarios that might trigger that can’t be identified, you can expect it to happen if the code causes theapplication to shut down The logic is that you would not want to save modifications that caused the appli-cation to crash But because it can be frustrating to lose other, desirable modifications, it’s prudent to saveyour changes as you go, as usual
to make it a breeze to work with other applications
Remember that you can download the code, databases, and other materials from the book’s website At
a minimum, the sample files make it easier to follow along; plus, they’ll help you avoid the potential fortypos or misreading characters or formatting
Trang 11VBA Basics
Now that you know a bit about automating Access, using macros, and how VBA fits into theAccess automation picture, you’re almost ready to write some code The next step is to reviewsome VBA basics
For experienced programmers, this chapter is unnecessary; however, if you’re just delving intoVBA from another programming language or from VBScript, this chapter contains vital informa-tion that will help you to better understand and utilize what you learn in subsequent chapters.Here you’ll examine the basic VBA programming objects, learn about variables and how to declarethem, and review some additional VBA structures that you’ll use in your code Along the way,you’ll build a few procedures, and you will soon gain the skill and confidence to modify thoseprocedures and to create your own
VBA Objects
You can’t program in VBA without understanding how the various VBA components worktogether All VBA code is comprised of individual statements Those statements take objects andmanipulate their properties, call their methods, and perform their events This section introducesthe concepts of objects, properties, methods, and events
VBA is an object-oriented programming (OOP) language OOP is a type of programming in whichprogrammers define a complete data structure from data types to the operations that can be applied
to the data structure Programmers can create an entire object that contains both data and the tions that the object can perform They can also create relationships between objects
opera-There are seemingly countless objects that you can work with using VBA The collection of objects
exposed by a particular application is called an object library You can incorporate multiple object
libraries in VBA For example, you can use VBA to manipulate the Access object library and workwith objects such as tables, queries, forms, and reports You can set references to other object librariessuch as Microsoft Outlook, Adobe Acrobat, or Microsoft Word (Appendix B provides an in-depthdiscussion of how to set and use references.) Every time you set a reference to another application’sobject library, you have access to all objects within that library An object is generally thought of as a
Trang 12physical thing For example, if you were to set a reference to a car’s object library, you could access all thecar’s objects, such as its tires, roof, carpet, steering wheel, and windows.
Properties
A property is a physical attribute of an object Each property can have multiple values For example, the
properties for a car object include color (silver), doors (four), and cylinders (four) However, the car hasobjects of its own The car’s tire object has a brand property of Michelin The car’s carpet object hasproperties of style(plush) and clean(true)
Some properties of an object can be easily changed If you want to change the value for the car’s erty color, you take it to an auto detailer and choose another color With one spilled latte, the carpet’sproperty cleanis turned to false However, you can’t easily change the number of doors on the car.And, short of completely replacing the engine, you can’t change the number of cylinders Similarly,objects in VBA have some properties that can be changed and some that cannot
prop-Additionally, every object in Access also has properties The formobject, for instance, has many ties including Border Style, Width, Height, and Caption Each of these properties has range of possi-ble values The Border Styleproperty, for example, can be set to None, Thin, Sizable, and
proper-Dialog—each choice presents the form object with a slightly different look Before you start ing properties in VBA code, take a look at the object and examine some of its properties In the case of aform, launch the form in design mode and change some of its properties Then run the form to see howthe changes affect not only the display but also the operation of the form (Forms and controls generallyhave quite a few properties and options, but they’re relatively logical and you typically work with only afew You’ll learn more about forms in Chapter 10.)
manipulat-Methods
A method is an action that can be performed by, or on, an object When you’re in your car, you can invoke
the start method of the engine, invoke the release method of the parking break, invoke the shift method
of the transmission, and invoke the press method of the gas pedal Each of these methods causes thing to happen If things work according to your programming, the car goes forward (which can bedescribed as causing the drive method to be executed on the car itself) Generally, an action or event thathappens (such as driving) is made up of many other methods performed on multiple objects
some-Objects in VBA have methods, as well For example, you can invoke the LoadPicturemethod on anActiveX control within an Access form; this causes a picture to be displayed within the control One ofthe frequently used methods moves the cursor to the next record in a DAO recordset:
rst.MoveNext
Events
An event is something that happens to an object The car turns when you turn the steering wheel The
horn blares when you press it The door closes when you pull it Turning, blaring, and closing are allevents of the car Events and methods are related in a cause-and-effect way An event happens when theuser does something The actual doing is the method So you invoke the move method on the wheel andthe car invokes the turn event It’s sometimes difficult to grasp the difference between the two; it’ll
Trang 13When you open an Access form, you actually raise (or cause to happen) the OnOpenevent When youclose the form, you raise the OnCloseevent Within code, however, you can invoke the Openmethod ofthe form Invoking the Openmethod causes the OnOpenevent to fire So, invoking a method causes anevent to happen or fire.
Now that you know a bit more about properties, methods, and events, you’re ready for a brief review ofthe fundamentals of VBA programming
Variables and VBA Syntax
This section goes over some basics you need to know to program successfully in VBA Most of themneed only to be recapitulated, so if you need more information about any of these topics, you might
want to purchase a beginner’s guide to VBA programming, such as VBA For Dummies, by John Paul
Mueller (Wiley Publishing, Inc., ISBN 0764539892) Of course, the help features in Access and VBA alsoprovide guidance on specific tasks or features
Variables
One of the most important concepts in programming is the use of variables A variable is a location in
memory where you can store a value while your code is running VBA only needs to find an item’s tion the first time it is used in code; it does not need to look up the location each time For example, ifyou need to specify a particular state repeatedly in your code, it can be much faster and cleaner to create
loca-a vloca-ariloca-able strStatethan to repeatedly use Washingtonin your code Not only will the code run faster,but if you ever need to switch states and use Californiainstead, all you have to do is change the value
of your variable rather than find all instances of Washingtonin your code
Using variables can also make your code easier to interpret They not only define what VBA allows inthe field, but they let you and other developers know what the field can be used for
Variables hold a variety of types of data including strings, numbers, and objects As you’ll see shortly, astring variable is basically any combination of alpha or alphanumeric data, such as a phrase or name.Although it can store numbers, the numbers will not function as numbers in equations This is explained
a little later, too The number types store values that can be used in mathematical equations Objectsinclude database objects and collections
Properly declaring variables is one of the most important tasks you need to master to program in VBA.It’s not hard, but it is a critical skill, and you’ll explore the major rules and recommendations for vari-ables in the next few sections
Variable Data Types
In VBA, you can declare many different types of variables Variables are named by the type of data thatthey are designed to hold Make it a point to declare your variables with the correct type so that yourcode runs as efficiently as possible and provides more descriptive error messages If you choose to notdeclare a data type, the variable is created as a variant Variant variables are slower then explicitlydefined data types and require significantly more space in memory than other types of variables Thefollowing table lists the variable data types, the amount of memory they take, and the range of valuesthat they can store
Trang 14Data Type Size in Memory Possible Values
Long(long integer) 4 bytes –2,147,483,648 to 2,147,483,647
Single(single-precision real) 4 bytes Approximately –3.4E38 to 3.4E38
Double(double-precision real) 8 bytes Approximately –1.8E308 to 4.9E324.Currency(scaled integer) 8 bytes Approximately
–922,337,203,685,477.5808 to922,337,203,685,477.5807
Decimal* 14 bytes With no decimal places, the range is
+/–79,228,162,514,264,337,593,543,950,
335 or with decimal places, the range is+/– 1E–28 (one to the 28th power) Thesmallest possible non-zero number is0.000,000,000,000,000,000,000,000,000,1written +/–1E-28
String - variable length 10 bytes + string length Variable length: ≤ about 2 billion
String – fixed length String length Up to 65,400
Variant - Number 16 bytes for numbers Same as double
Variant - String 22 bytes + string length Same as string
*The Decimal data type is included in this table although it cannot be used as a variable in a Dim statement Rather, the Decimal data type can be a Variant subtype using the CDec()function.
Notice that the VBA data types are similar to the data types in an Access table The major differencesbetween Access data types and VBA data types are that there is no equivalent to the variant or objectdata types in Access data types, and the Access Numberdata type has a field size property that enablesyou to specify the field as Byte, Integer, Long, Single, Decimal, or Double Access has one othernumber data type that VBA doesn’t: GUID, which can be 16 bytes It’s used for ReplicationId Properlyspecifying the field size this way saves memory and improves performance
Number Data Types
When working with numeric data, you have a choice of seven different data types: Long, Double, Byte,Integer, Single, Currency, and Boolean This section provides a brief introduction to data types and
Trang 15Each numeric data type provides a different level of accuracy, and they also use differing amounts ofspace You can follow some general rules of thumb when choosing the right data type for your variable:
❑ When creating a variable to store whole numbers, choose the Longdata type
❑ When creating a variable to store fractional numbers, choose the Doubledata type
❑ To store a negative value, use Integer, Single, Double, Long, Currency, or Decimaldatatype
❑ If you need to store a value outside the range of –32768 to 32767, do not use the Integerdatatype because it can’t handle numbers that large or small
❑ To control loops, always use an Integerdata type
❑ The Booleandata type is often used in Yes/No or True/False scenarios Any non-zero numberevaluates to True (or Yes)
❑ ReplicationIDis used only for replicated databases Although Access 2007 supports tion using the MDB file format, the new ACCDB file format does not support replication.There are a few key differences between the Singleand Doubledata types The Singledata typeallows you a precision level of 7 digits, whereas the Doubledata type gives you approximately 15 digits
replica-of precision Both data types allow you to work with numbers larger than 2 billion
You should never use Doubleor Singledata types to represent fractional numbers These cannot do sowith extreme accuracy (Although you may not notice the error for a while, those things tend to comeback to haunt you at the most inopportune times.) Here’s an example of using a Doubledata type with afraction in a loop:
Sub TestFractionalDivision()
‘Do not actually run this code!
‘If need be, use Ctrl+Break to stop code executionDim dblResult As Double
dblResult = 1 / 5
‘Demonstrates that dblResult will never truly equal 1
Do Until dblResult = 1
‘The following line is and alternative comparison
‘that will evaluate and stop execution
‘To test this, comment out the previous Do statement and
‘Remove the comment mark from the following Do statement
‘Do Until dblResult >= 1
‘Do something interesting –
‘In this case, start with 1/5 and keep adding 1/5 to the result
dblResult = dblResult + 1 / 5Loop
End Sub
Trang 16The loop will run forever because the value of dblResultnever actually equals 1 You’ll have to use Ctrl+Break to end this code loop That’s why you’re always better off using integers for loopingoperations.
An alternative is to use a comparison of greater than or equal to one (>= 1), as shown in the comment inthe preceding example This approach may result in an extra iteration, but it does stop
The Singleand Doubledata types are floating-point data types So they can handle numbers with thedecimal point in a variety of places The Currencydata type is a fixed-point number, meaning that thereare always four decimal places in a currency number to handle most types of international currency (ofcourse, you don’t need to display four decimal places) Just because the currencydata type is generallyused for dealing with dollars and cents, it’s not limited to financial transactions You can use the cur-rency data type for any number with up to four decimal places
Because the decimal is always in the same place, VBA actually performs a little trick with currency culations It removes the decimal points, performs the calculation on the integer numbers, and then puts the decimal points back This speeds up the calculation while retaining the four-decimal-place accuracy.
cal-Boolean Data Type
In addition to typical numeric data types, you can use a variety of other data types Booleanvariablescan take only two values, Trueand False If you’ve ever used VBScript, you’re probably familiar withusing numeric values to represent true and false When you refer to a Booleandata type in VBScript, 0
is false and -1is true You can still use these values with Booleandata types VBA interprets 0as false,but it is critical to remember that any non-zero value is always interpreted as true The following twocode examples, for instance, produce the same result:
The Date Data Type
Remember the Y2K bug? Computers used to store dates with only two-digit years, which caused a lem when computers needed to start storing dates past the year 1999 After all, 01 could be a two-digityear code for 1901 or for 2001 Programmers scrambled for several years to fix the problem So now com-puters store dates with a four-digit year However, that wasn’t the only problem with dates Differentcountries represent dates in various formats For example, the date 4/1/2007 could represent eitherApril 1, 2007, or January 4, 2007, depending on the region of the world in which you live To work
Trang 17prob-around this challenge, VBA has a nifty way of dealing with dates All dates are represented as a point number (one with a flexible number of decimal places) When working with a date and time, thedate portion is converted to an integer The time is represented by the decimal portion of the numberand is calculated as a percentage of a day For example, noon would be half of a day and represented by0.5 To determine the integer value for the date, an initial date is needed for calculations Access usesDecember 30, 1899 as day 0, so April 1, 2007 would be represented as 39173, so it follows that 6:00 P.M onthat date is represented as 39173.75.
floating-Rest assured that when you’re working with dates in VBA, you do not have to perform conversionsbetween 39173.75 and April 1, 2007, 6:00 P.M VBA is aware of the regional settings specified in the user’sControl Panel Regional Settings applet and converts the date to the proper format So, if you’re inAustralia, VBA converts 39173.75 to 01/04/07 If you’re in the United States, VBA displays 04/01/07 (or04/01/2007 depending on your settings) VBA’s use of calculated numbers for dates ensures that datesare always calculated correctly regardless of the specific regional settings used on the local computer.And, of course, you can further control how dates and times are displayed through code, as well as with
a control’s Formatproperty
Here’s a brief example to illustrate how to work with VBA date calculations As mentioned, a variabledeclared as a date has an initial value of December 30, 1899 (or 0when converted to the floating-pointdecimal value) The following code produces a value of December 31, 1899
Sub AddADay()Dim dtInitialDate As DatedtInitialDate = DateAdd(“d”, 1, dtInitialDate)Debug.Print dtInitialDate
End SubYou can work with dates directly in VBA by assigning the literal date value to a date variable To do so,use #to delimit your date For example, to assign a value of April 1, 2007, to the variable
dtInitialDate, use the following code:
dtInitialDate = #04/01/2007#
That ensures that VBA will recognize the date properly no matter what your regional settings are.However, if you’re in a region of the world that enters dates with d/m/yyyy, you’ll need to enter the lit-eral date in the format m/d/yyyy when using this method Otherwise, VBA won’t recognize it properly
The String Data Type
The Stringdata type is fairly straightforward You use it for all types of alphanumeric data includingnames, sentences, or phrases Numbers stored as a string data type respond to sorts and calculations ascharacters rather than numbers, as illustrated in the following code snippet:
Sub FunWithStrings()Dim strBikes As StringDim strCost As StringDim intBikes As IntegerDim curCost As CurrencystrBikes = “5”
Trang 18strCost = “100”
intBikes = 5
curCost = 100
Debug.Print strBikes + strCost
Debug.Print intBikes + curCost
End Sub
The first operation, Debug.Print strBikes + strCostproduces a result of 5100 Because these aretext values, the operation concatenates the two string variables The second operation involves numericdata types, so Debug.Print intBikes + curCostactually performs the mathematical calculation andproduces a result of 105 You’ll immediately notice the impact when sorting a string of numbers When creating a string variable, the default value of the variable is a zero-length string It isn’t the same
as a Nullvalue; it’s more like an empty value You can assign pretty much any value to the string able The trickiest problem you’re likely to encounter while using string variables in VBA is dealing withquotation marks within the content of the string For example, the following is a valid way to assign astring value to a variable:
vari-strCustomerName = “ABC Textiles”
The same syntax works if you need to store a value with a single quote in the name, such as the following:strCustomerName = “Johnny’s Cycles”
What if you need to store a value with a double-quoted character in the name? If you follow the samerules as the previous two examples, you end up with something like the following:
strCustomerName = “The “W” Hotel, New York City”
It might look like a valid line of code, but when you actually type that into your code, you’ll get a pile error before you run the code The problem is that VBA sees the second double quote and thinks youwant to end the string VBA doesn’t quite know what to do with the text that follows that quote Towork around the issue, you use a double set of double quotes within your string, basically quoting thequote, so that your actual assignment statement looks like the following:
com-strCustomerName = “The “”W”“ Hotel, New York City”
If you enter all strings with double quotes using that method, you’ll get predictable results every time
String Comparisons
You can’t have a discussion about string variables without discussing how to work with strings Keeping
in mind that strings are typically text or alpha-numeric, some of the most common tasks you’ll perform
Trang 19with strings include comparing two strings, finding matches to a partial string, or determining the length
of a string The next few paragraphs describe some of the tricks you can use to work with string variables.When comparing two strings, you’ll find that VBA is not case sensitive by default In other words,Californiaand CALIFORNIAare considered to be the same string You can change this default behav-ior by editing the first line of your VBA code When opening a module in VBA, the first line is OptionCompare Database Changing this line to Option Compare Binaryhas one immediate effect: Allstring comparisons are now case sensitive The following table provides a summary of the three optionsyou can select for the Option Comparestatement in VBA Keep in mind that these statements are mod-ule specific, so they only affect the module that they are in
Compare Statement Definition
Option Compare Database String comparisons are case insensitive Local settings of the
current database are used
Option Compare Binary String comparisons are case sensitive Local settings of the
current database are ignored
Option Compare Text String comparisons are case insensitive Local settings
speci-fied in Control Panel are used This setting is seldom used
Unless you have good reason to change the Option Comparestatement, leave it at the default value ofOption Compare Database (You’ll probably find that the default value is used in more than 99 percent
of the modules.)You don’t always have to compare entire strings to each other You can search for strings based on one
or more characters in the string For example, the following code illustrates a couple of types of stringcomparisons
Sub CompareStrings()Dim strString1 As StringstrString1 = “Microsoft”
If strString1 Like “Micr*“ ThenDebug.Print “True”
End If
If strString1 Like “Mic*t” ThenDebug.Print “True”
End IfEnd SubBoth of these comparison operations return True The first returns Truewhenever the first four letters
of strString1are Micr The second comparison returns Truewhenever the first three letters ofstrString1are Micand the last letter is t
Trang 20The following table lists the key wildcards used for string comparisons.
Character Description
?or _(underscore) Single character
Keep in mind that characters are alpha, numeric, and special The following table shows the variety ofcomparison operations that you can use in VBA
Comparison Expression Strings That Match Strings That Do Not Match
Like “Mi*“ Microsoft, Michigan MapPoint, Monochrome
Like “177#“ 1776, 1777, 1778, and so on 1977, 177, 1077
Like “s[aeio][aeio]t” seat, soot set, sat
As you can see from the table, the rules are fairly straightforward The last three examples are the mostconfusing Using two characters (or more) within the brackets tells VBA that any of the characters withinthe brackets can be used within the string; that means that a match can contain any one of the characters.Putting the exclamation point inside the brackets and before the characters tells VBA that any characterexcept those within the brackets can be used to compare the string Using two sets of bracketed charac-ters tells VBA to match two characters—one from each set You can also enclose a range in the brackets—for example, 3–6 would indicate the numbers 3, 4, 5, and 6
Variants
The Variantdata type is probably the most flexible data type within VBA Unlike other variable types,which can only hold one type of data, the variant data type can hold many different types of data Youcan use it to hold text, numbers, dates, and user-defined types The only type of data a variant data typecannot hold is a fixed-length string As previously explained, there is a price to be paid for such flexibil-ity As tempting as it might seem to use variant data types for all of your coding, the practice results inmuch higher memory use and means a performance hit compared to using the proper data type Forexample, using a variant to hold a string of data requires 11 extra bytes of data for every string you store.Over the course of an entire application, these extra bytes can have a significant performance impact
Trang 21There are times, however, when you need to use a variant data type For example, if you’re not sure what type of information a variable needs to hold, it is likely best to use the variant data type Most often,this type of unknown or unpredictable data configuration occurs when users are entering data in a rela-tively unstructured manner, such as on Web forms If you’re not sure whether users will enter a date, anumber, or a string, you can create a variantdata type and store the input in that variable Another place
to use a variant is for the variable of a function return Look at this code segment:
MyField = DLookup(“Lastname”, “Employees”, “[Lastname] = ‘Doe’”)Even though you know the answer will be a string, if Doedoes not exist, DLookup will return a Nulland an error will be generated if MyFieldis declared as a string Of course, there are other ways to han-dle Nulls, but this will work and it provided such a good segue
Nulls
We should discuss another important concept when talking about variables, and that is Null When youfirst learn programming, you learn that Nullis the value of a field with no data If you create a field in atable and don’t fill it with any data, the value of the field is Null So what is Null? Nullis nothing, butNullis also something It sounds a bit confusing, because it is Here’s an example to help demonstratejust how mind-boggling Nullcan be
Sub CompareNulls()Dim varValue1 As VariantDim varValue2 As VariantvarValue1 = Null
varValue2 = Null
If varValue1 = varValue2 ThenDebug.Print “Nulls are equal”
End IfEnd Sub
If you run this code, you’ll see that the phrase never prints in the Immediate window But how can thatbe? You just set the two variables equal to the same value Well, you might think you set them to thesame value, but really, two Nulls never equal each other
There are two rules to remember when working with Null First, you cannot assign Nullto anythingother than a Variant data type So, you can never have a Nullstring; instead you have a zero-lengthstring You cannot have a Nullsingle or double (numeric data type); instead you have a variable withvalue 0 The second rule of Nullis, as previously demonstrated, that no two Nulls match Nulldoesn’tmatch zero; it doesn’t match a zero-length string; it doesn’t even match itself The only comparison oper-ation you can run on Nullis to determine whether it is Null But, as mentioned previously, Nullneverequals Null If you’re thinking, great, now what can I do?, you’ll be relieved to learn that there are rela-
tively straightforward processes to test for and work with Null And, by slightly modifying the previouscode sample, you get a completely different result and the print phrase will appear in the Immediatewindow, as shown in the following example:
Sub CompareNulls2()Dim varValue1 As Variant
Trang 22Dim varValue2 As Variant
varValue1 = Null
varValue2 = Null
If IsNull(varValue1) And IsNull(varValue2) Then
Debug.Print “Both variables are Null”
End If
End Sub
This code sample prints the phrase in the Immediate window By independently testing each variable for Null, you can compare the results You test for the Nullcondition by using the IsNullfunction,which evaluates to Trueif the value of the variable is Nulland to Falseif the value of the variable isnot Null
Just remember the two basic rules of Null Nulldoesn’t equal anything and Nullequals nothing.
Nullsalso react differently when used in mathematical formulas instead of string operations To quicklytest what happens, enter these simple lines with the question marks in the Immediate window For illus-tration purposes, the results are included after each example Remember that “5”is a string
?5 + Null ‘ number with a math formula
mid-Public Function Which2Use()
Dim strMI As Variant ‘Declared as a variant so that you can use a Null value.strMI = Null
Debug.Print “John” & “ “ & strMI & “ “ & “Doe - Null with & (string operator)“Debug.Print “John” & “ “ & strMI + “ “ & “Doe - Null with + (math equation)“Debug.Print
strMI = “P”
Debug.Print “John” & “ “ & strMI & “ “ & “Doe - P with & (string operator)“Debug.Print “John” & “ “ & strMI + “ “ & “Doe - P with + (math equation)“
End Function
Trang 23The results are:
John Doe ‘ Null with & (string operator)John Doe ‘ Null with + (math equation)John P Doe ‘ P with & (string operator)John P Doe ‘ Null with + P with + (math equation)The first example with Nulluses a string operator to concatenate the values, so the period and extraspaces print The second line uses the numeric plus function; Nulladded to a period and space returnsNull, so the period and space are removed
In the second set of examples, Nullis not a factor, so adding and concatenating text yield the sameresult
User-Defined Data Type
VBA provides a way to group different data types under one heading This creates an object with a set ofproperties You define the group with the word Typeon a Module level and by default it is Public Youcan use the Privatekeyword if you want to restrict it to the module only Here’s an example:
Option Compare DatabaseOption Explicit
Public Type WeatherElementsType As String
Temp As SingleProtect As BooleanEnd Type
Public Function Action()Dim Yesterday As WeatherElementsDim Today As WeatherElementsToday.Type = “Sunny”
Today.Temp = 64.3Today.Protect = FalseYesterday.Type = “Snow”
Yesterday.Temp = 31.2Yesterday.Protect = TrueDebug.Print “The weather took a turn for the better!”
Debug.Print “Readings: Yesterday Today”
Debug.Print “Weather: “ & Yesterday.Type & “ “ & Today.TypeDebug.Print “Temperture: “ & Yesterday.Temp & “ “ & Today.TempDebug.Print “Protection: “ & Yesterday.Protect & “ “ & Today.ProtectEnd Function
Trang 24As you can see, several elements (data types) are grouped under the object WeatherElementsand anew data type is assigned to two different variables By using the variable name followed by the dot andthen the element name, you get the value of that element When you run the preceding code sample, this
is what you should see in the Immediate window
The weather took a turn for the better!
Readings: Yesterday Today
Weather: Snow Sunny
As mentioned earlier, it is good programming practice to declare all of your variables This practiceensures that your variables have the proper types and can speed code execution Additionally, if youdon’t declare your variables, they can actually get you into trouble The following code sample illus-trates this:
Sub BuyNewBike()
Dim curBikePrice as Integer
curBikePrice = InputBox(“Please enter bike price.”, “Enter Bike Price”)
to buy the bike If the price is less than $100, you can buy the bike
However, the code won’t actually work Examine it carefully and you’ll see that the variable that acceptsthe price of the bike, curBikePrice, isn’t the same as the variable used in the If Thenstatement,curVikePrice A mistake like that is quite easy to make You’re typing along and you hit the wrongkey You probably wouldn’t even notice it until you run the code and nothing happens As it’s written,there’s actually nothing wrong with the code It won’t produce any errors; it just won’t produce therequired results
Trang 25There is one easy way to prevent this type of mistake, and that’s the VBA option mentioned earlier Justadd a single line of code to the General Declarations section of your code: Option Explicit These twowords tell VBA that all variables used in your module must be declared before they can be used If youforce variable declaration, then typing the wrong name for a variable causes VBA to display an errorwhen the code is compiled, as shown in Figure 5-1.
Figure 5-1
Once the error message is displayed, VBA highlights the undeclared variable(s), so that you can quicklysee and correct the errors For this situation, it is to either correct the spelling of the variable to match thedeclared variable or to add a new line of code to declare the variable used in your code
Always use Option Explicitin your modules You can configure Access to do this for you From where in the Access VBA Editor, select Tools➪ Options Choose the Editor tab and check the boxmarked Require Variable Declaration Click OK to save your changes Now, whenever you create a newmodule or build code behind any Access form or report, you’ll be prompted to declare your variables.The Editor only adds Option Explicitas new modules are created, so you will need to insert thatphrase at the top of each existing module
any-Declaring Variables
You declare a variable by use of the Dim(short for dimension) keyword, and then the variable name, lowed by the word As, and then the variable type For example, the following statement declares thestate variable in your procedure:
fol-Dim strState As String
Once you dimension your variable, you can assign it a value anywhere in your procedure For stringvariables such as strState, use the following statement to assign the value “Washington”:strState = “Washington”
Trang 26Now that your variable has a value, you can use it repeatedly within your procedure Consider the lowing code segment:
fol-Private Sub OpenDatabaseConnection()
Dim objConn As ADODB.Connection
Dim objRST As ADODB.Recordset
Dim strSQL As String
Dim strConn As String
Dim strState As String
‘Create the ADODB Connection and Recordset Objects
Set objConn = CreateObject(“ADODB.Connection”)
Set objRST = CreateObject(“ADODB.Recordset”)
‘Open your ADODB Connection
strConn = “Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:\Cust.mdb;”
strSQL = “Select * from tblCust WHERE CustState = ‘“ & “Washington” & “‘;”
objConn.Open (strConn)
objConn.Mode = adModeRead
objRST.Open strSQL, objConn, adOpenForwardOnly, adLockOptimistic
objRST.MoveFirst
‘Print relevant customer information
While Not objRST.EOF
Debug.Print objRST.Fields(“CustName”)Debug.Print objRST.Fields(“CustState”)Debug.Print objRST.Fields(“CustCountry”)objRST.MoveNext
Wend ‘while end – closed the while loop
do so You could adapt the previous code through the use of a variable and input box to allow users toselect the state they need Here’s how that code might look:
Trang 27Private Sub OpenDatabaseConnection()Dim objConn As ADODB.ConnectionDim objRST As ADODB.RecordsetDim strSQL As String
Dim strConn As StringDim strState As String
‘Create the ADODB Connection and Recordset ObjectsSet objConn = CreateObject(“ADODB.Connection”)Set objRST = CreateObject(“ADODB.Recordset”)
‘Open your ADODB ConnectionstrConn = “Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:\Cust.mdb;”
strState = InputBox(“Please enter a state”, “Enter State”)strSQL = “Select * from tblCust WHERE CustState = ‘“ & strState & “‘;”
objConn.Open (strConn)objConn.Mode = adModeReadobjRST.Open strSQL, objConn, adOpenForwardOnly, adLockOptimisticobjRST.MoveFirst
‘Print relevant customer informationWhile Not objRST.EOF
Debug.Print objRST.Fields(“CustName”)Debug.Print objRST.Fields(“CustState”)Debug.Print objRST.Fields(“CustCountry”)objRST.MoveNext
WendobjRST.CloseobjConn.Close
‘Release your variablesSet objRST = Nothing
Set objConn = NothingEnd Sub
Using the preceding code, users can enter any state in response to the input box and your code will runand return the appropriate records
There is still a key element missing from this procedure—error handling As you know, or will soon cover, in addition to trapping for events triggered by code, error handling can help control what usersare able to do and how data is handled For example, if users enter Sacramento as a state, misspellMississippi, or simply choose a state for which no records exist in your database, the preceding code willgenerate an error Chapter 9 focuses on error handling
dis-Naming Your VariablesThere are a few rules to follow when naming a variable:
❑ Use only letters, numbers, and the underscore symbol (_) No other symbols are allowed
Trang 28❑ Variable names must start with a letter.
❑ Do not use a reserved word for your variable name
❑ Variable names must be less than 255 characters
Special characters and reserved words are discussed in Appendix K.
In addition to the rules you must follow when naming your variables, it’s customary to follow some sort
of naming convention when creating your variables While you may choose any convention, the mostpopular is the Reddick naming convention Appendix L provides detailed information about this nam-ing convention, and guidelines for creating your own naming conventions Although developers havethe latitude to implement a recognized convention, to modify a convention to fit their style, or even toignore conventions, it’s strongly recommended that you at least create meaningful variable names.Meaningful names not only make it easier to read through the code, but they minimize conflicts andfacilitate debugging If you create variables with names such as var1, var2, and var3, you’ll have ahard time keeping track of which variable you need to use for which statement
This book sticks pretty closely to Reddick’s naming conventions So variables usually contain a
prefix that determines their data type A string variable, for example, will ususally have the str
prefix, such as strSQLand strMsg,whereas a Boolean variable will have a blnprefix, such as
blnUnderBudgetand blnCurrentMeeting.
In addition to Reddick’s naming conventions, some developers like to use an additional convention tomake their code easier to interpret: adding a prefix to variable names to denote whether the variable is aglobal, private, or local variable The following table describes the prefixes used to denote variable scopeand lifetime
Prefix Variable Scope Examples Usage
Publickeyword
m Private (module-level) variables mSalesTotal Variables declared with the
Privatekeyword
the Statickeyword
Variable Scope and Lifetime
The scope of a variable defines where in the program the variable is recognized The lifetime of a variable
describes how long it will persist
If you declare your variable within a sub or function, the variable’s scope is limited to that sub or tion only That’s why you don’t need to worry about variables conflicting with each other if you use thesame name for a variable in another sub or function The lifetime of that variable is the same as the sub
func-or function—the variable lives only while the sub func-or function is running As soon as the procedure ends,
Trang 29the variable is destroyed and the memory used by the variable is released A subsequent call of the cedure creates the variable again and it has no memory of the previous existence.
pro-At times you want your variable to exist outside of a particular sub or function If you declare the able in the General Declarations section of the module (located at the top of the module), your variablecan have a longer scope and lifetime You can declare the variable in two ways:
vari-❑ Use the Privatekeyword to make the variable available to any and all procedures within thecurrent module
❑ Use the Publickeyword to make the variable available anywhere in the entire application.The following code sample illustrates how both the declaration and its location affect a variable’s scopeand lifetime:
Option Explicit ‘Used to require variable declarationPublic txtCustomerName as String ‘Scope is entire applicationPrivate txtVendor as String ‘Scope is any procedure in this moduleDim txtSupplier as String ‘Scope is the current module
Private Sub GetCustomerName()Dim txtCustomer as String ‘Scope is limited to this subEnd Sub
You might be wondering why the two statements that begin with Dimhave different scopes Use of theDimkeyword in the General Declarations section sets the scope of the variable to the module so it can beused by any procedure in that module In the previous listing, txtVendorand txtSupplierare bothmodule-level variables They can be used anywhere within the module and anytime the module isloaded txtCustomerNameis a global variable It can be used anywhere within any procedure in theapplication
Use of the Statickeyword enables you to create a local variable with an ongoing lifetime There areseveral reasons why you might want to do this If you needed to know how many times a particular pro-cedure was run, you could simply declare a global variable and increment this variable every time theprocedure runs However, it’s often easier to track the use of variables when they are declared within theprocedure in which they’re used There’s one big difference between using the Statickeyword withinthe procedure and using the Publickeyword in the General Declarations section to declare your vari-ables If you declare the variable with the Publickeyword in the General Declarations section, you canuse the variable anywhere within your application If you use the Statickeyword within a procedure,you can only use the variable within that procedure The key thing is that the variable isn’t destroyedwhen the procedure completes The variable remains and retains its value for the next time that proce-dure is called Keep in mind that the variable is still dedicated to the one procedure, so you cannot usethe Statickeyword to create a variable within Procedure A and use it within Procedure B
Overlapping VariablesWhen writing code, be careful to use a variable name only once If you declare a global variable ofstrStringand then declare a variable within your procedure named strString, VBA will always usethe procedure-level variable If you are using procedures to call routines in other procedures, you may
Trang 30forget that one has a variable with the same name as a global variable, and that can create unexpectedresults Here’s an example:
Option Compare Database
Option Explicit
‘this module demonstrates that local variables
‘take precedence over global variables
Public intQuantity As Integer
Public curPrice As Currency
—————————————————————————————————————————————————————————————————————————————————————Private Sub FindTotals()
Dim intQuantity As Integer
Dim curTotalPrice As Currency
‘this sub declares the local variable intQuantity
‘but does not give it a value, so the value is 0
curPrice = InputBox(“Please enter the bike price.”,_
“Enter Bike Price”)
curTotalPrice = intQuantity * curPrice
MsgBox curTotalPrice, vbOKOnly, “Total Price”
End Sub
—————————————————————————————————————————————————————————————————————————————————————Private Sub EnterValues()
‘this is storing the value into the global variable
intQuantity = InputBox(“Please enter the number of bikes”, _
“you want to buy.”, “Total Bikes”)End Sub
—————————————————————————————————————————————————————————————————————————————————————Private Sub CalculatePrice()
‘This sub runs the two subs listed below
‘Although Enter Values stores a quantity in the
‘global Variable, intQuantity, the FindTotals sub will
‘use the local variable intQuantity to calculate curTotalPrice
Trang 31with the same name as the public variable declared in the General Declarations section of the module.Because there is no input for this local variable, it uses the default value of 0 The procedure uses thelocal variable instead of the global any time intQuantity So the equation curTotalPriceyields 0asits result.
If you want Access VBA to use the global variable, you can add the module’s name before the variablename The following code works as intended:
Option Compare DatabaseOption Explicit
‘this module demonstrates that by explicitly naming a variable
‘with both the module and variable name, value of the global
‘global variable will be used mintQuantity would also work
Public intQuantity As IntegerPublic curPrice As Currency
—————————————————————————————————————————————————————————————————————————————————————Private Sub FindTotals()
Dim intQuantity As IntegerDim curTotalPrice As Currency
‘This sub declares the local variable intQuantity
‘but does not give it a value, so the value is 0
‘replace [ModuleName] with the name of the current module
curPrice = InputBox(“Please enter the bike price.”,_
“Enter Bike Price”)curTotalPrice = [ModuleName].intQuantity * curPriceMsgBox curTotalPrice, vbOKOnly, “Total Price”
End Sub
—————————————————————————————————————————————————————————————————————————————————————Private Sub EnterValues()
‘this is storing the value into the global variable
intQuantity = InputBox(“Please enter the number of bikes”, _
“you want to buy.”, “Total Bikes”)End Sub
—————————————————————————————————————————————————————————————————————————————————————Private Sub CalculatePrice()
‘This sub runs the two subs listed below
‘Although Enter Values stores a quantity in the
‘global Variable, intQuantity, the FindTotals sub will
‘use the local variable intQuantity to calculate curTotalPrice
EnterValuesFindTotalsEnd Sub
Trang 32Adding the name of the module in front of the variable name is an easy way to tell Access VBA exactlywhich variable you need You’ll also recall that some developers like to use a prefix to specify the vari-able scope Using mintQuantityin the General Declarations section would have prevented the overlap.It’s best, however, to avoid this situation entirely Utilize naming conventions and declare your variableswith as narrow a scope as you need If you don’t need to declare a public variable, it is better to use aprocedure-level variable For your convenience, these two modules are included in the download codefor this chapter.
Other VBA Str uctures
You’ll often use a few other VBA components within your code: comments, constants, and to a lesserextent, enums This section provides a brief introduction to each and shows you how these componentscan be helpful within your code
Comments
VBA programming consists of writing statements and comments Although comments are not explicitlyrequired, they make it much easier to read the code and figure out what it is intended to do As you’veprobably noticed, uncommented code is hard to read and difficult to understand Comments are espe-cially helpful to someone else who may end up working with your code; of course, if it’s been a whilesince you’ve worked on a particular project, you’ll find that those comments can get you back up tospeed quickly
When working with the VBA Editor in Access, you can add comments by prefacing text with an phe The default setting is that comments appear in green, so they are quickly recognized when scanningthrough code Although you can insert comments at the end of a line of code, they are more commonlyused before or after a procedure or function Comments are ignored during code execution You canhave one or many lines of comments in a procedure, and VBA will ignore them all Comments don’tslow down the execution of your code; so you can use them liberally At a minimum, your commentsshould list what the procedure is for and when it was written Figure 5-2 shows a typical procedure with detailed comments—albeit these comments are primarily for training purposes
apostro-You might be wondering why you need to add comments to code you’re writing for your own tions Well, any time you write code, there’s a chance that it will be used for more than one application.It’s also possible that someone else will eventually inherit your code If you choose to take a new jobelsewhere, the replacement programmer your company hires might need to make changes to your code
applica-If you haven’t added any comments to your code, he’ll have a hard time understanding your dures If you’ve ever had to examine another programmer’s code and found it without comments, youunderstand the importance of comments
proce-Comments help you understand why you might have used a particular piece of code For example, ifyou hard coded certain values within your application, you might wonder why you chose to use thoseparticular values Comments can also provide invaluable notes during development and testing Youcan include notes about business rules and when to use one process instead of another During testing,comments are reminders about a problem created or solved by specific lines of code
Trang 33Figure 5-2
Line ContinuationStrategic line breaks also help make code easier to read and understand Many VBA statements are quitelong Take the following If Thenstatement used to fill a variable with a value:
If (txtCustomerState = “CA” And txtCustomerZip = “95685”) Or(txtCustomerState = “WA” And txtCustomerZip = “89231”) ThentxtCustomerRegion = “Western US”
End If
As you can see, this code is a bit long When printed in this book, even the conditional portion of thestatement takes up several lines When you write this code in VBA, all of the code will go on one verylong line Obviously, the line won’t all display on the screen, as shown in Figure 5-3 This can make pro-cedures difficult to read, as you need to not only scroll up and down to view the entire procedure butscroll left and right, as well
A line continuation character (an underscore preceded by a space) is used to break long lines of code into understandable, easy-to-read segments Although you are inserting characters, they are for visualappearance and do not change the meaning of the code The space/underscore at the end of a code line
Trang 34indicates that the next line is a continuation of the current line as in the following code snippet, as shown
in the second example in Figure 5-3 The benefit of using line breaks is evident
If (txtCustomerState = “CA” And txtCustomerZip = “95685”) Or _
(txtCustomerState = “WA” And txtCustomerZip = “89231”) ThentxtCustomerRegion = “Western US”
End If
Figure 5-3Strategic line breaks not only keep the code within the viewing pane, but they also help developers rec-ognize individual steps within a procedure There’s one limitation to the line continuation character,however; you can’t use it “as is” within literal strings If you’re using the line continuation character in astring, you must use the &symbol on the continued line and add extra quotation marks—one before thespace/underscore at the end of the line and one after &/space at the start of the next line Figure 5-4illustrates the following examples When opening a recordset with an SQL statement, you could end upwith a very long SQL statement to include all of the fields you need within your table The statementmight read something like the following:
strSQL = “SELECT [CustomerName], [CustomerCode], [CustomerAddress1],
[CustomerCity], [CustomerState], [CustomerZip] FROM Customers WHERE [CustomerState]
Is Not Null;”
You can use the line continuation character along with the & symbol to turn that code into the following:strSQL = “SELECT [CustomerName], [CustomerCode], [CustomerAddress1]“ _
& “, [CustomerCity], [CustomerState], [CustomerZip] FROM” _
& “ Customers WHERE [CustomerState] Is Not Null;”
Trang 35Use line continuation characters any time you have code lines longer than your screen width Keep inmind that you need to include the space that is used to separate words It can be placed after the lastcharacter at the end of the line but before the underscore, or between the quotation mark and the firstcharacter at the beginning of the next line Without the appropriate spaces, words can run together Sothe preceding example, might end up with “ … [CustomerZip] FROMCustomers WHERE…”
Public dtStartDate as Date = #10/23/2007#
A symbolic constant is much like a variable It is used for fixed values that won’t change in your code.They are usually declared at the beginning of your procedure by using the Constkeyword instead of theDimkeyword Specifying a constant for the width of a page is an example of a symbolic constant Often,the constant name is typed in all capital letters, as in this example:
Const PAGE_WIDTH = 80
As you’re reading and working through the examples, consider developing your own list of conventions
to add structure and consistency to the format and layout of your code.
You can declare literal and symbolic constants in several ways, such as in the General Declarations tion or within a procedure and declaring it as Publicor Privateto stipulate the scope Constants fol-low many of the same rules that variables do, plus a couple more of their own They must have a uniquename, and not just within the ones you create You cannot create a constant with the same name as abuilt-in constant And once you have created a constant, you cannot change it or its value
sec-Built-in constants are defined within VBA, either by a program or by the system They help you code byenabling you to learn the constant name rather than the number associated with the constant’s value.For example, VBA provides constants for such uses as defining the types of buttons you see on a mes-sage box Rather than use the number that corresponds to the Yesor Nobutton option in a message box,you can use the constant vbYesNo Because the constant has a somewhat intuitive name, it is relativelyeasy to remember You call a built-in constant by simply using its name All built-in constants in VBAbegin with the letters vb There are approximately 700 built-in constants in VBA Thankfully, you don’tneed to learn about all 700 In fact, you will likely use only a small percentage on a regular basis
The following table describes some of VBA’s built-in constants As you can see, there are constants for allsorts of VBA operations If you’re curious about the entire list of VBA constants, you can view them inthe Object Browser To open the Object Browser from the VBA window, you can simply use the shortcutkey F2 or you can select View➪ Object Browser
Trang 36Constant Name Value Purpose
vbFirstFourDays 2 Configures the first week of the year to be the
first week with at least four days
vbFirstFullWeek 3 Configures the first week of the year to be the
first full (7-day) week
vbOkOnly 0 Describes a type of message box with only an
OK button
vbYesNoCancel 3 Describes a type of message box with three
but-tons: Yes, No, and Cancel
vbMonday 2 Constant used to specify Monday as the day of
the week
vbWednesday 4 Constant used to specify Wednesday as the day
of the week
vbHidden 2 Used to describe the hidden attribute of a file
Each object library that is referenced within your code contains its own set of built-in constants For ple, in Microsoft Access there are seven built-in constants to specify a type of form view: acViewDesign,acViewLayout, acViewNormal, acViewPivotChart, acViewPivotTable, acViewPreview, andacViewReport Using the built-in constants in your code is a lot easier than remembering that you need
exam-to specify the number 1 exam-to open a form in design mode Each object library has its own prefix All built-inconstants in Access use the prefix ac; in Outlook the prefix is ol; and in Word constants begin with wd You’re probably wondering how to find out if there are constants that you could use in your code Well,one way is to just start invoking properties, methods, and events One of the great advantages of VBA isthat once you start typing, VBA helps you along by providing IntelliSense, at least for many objects andcommands and providing that you use the dot (.), not the bang (!)
When you start typing the message box function, VBA prompts you to choose the proper constant forthe type of buttons you need Figure 5-5 illustrates how IntelliSense provides syntax prompts, as it doeswith the message box
Figure 5-5
Trang 37When working with commands and objects, IntelliSense prompts with available commands, objects,arguments, and syntax So, when you type the period (dot) after DoCmd—DoCmd.—a drop-down list dis-plays available actions and the list is updated based on the letters that you type Similarly, if you typeforms., you get prompts specific to the forms collection; if you type form., you can scroll through andclick to select the correct item from the list of events and properties for a form (see Figure 5-6).
Figure 5-6
Using the spacebar moves the cursor to the next prompt; pressing Enter ends the IntelliSense session andmoves the cursor to a new blank line
Enums
Both Access and VBA contain another structure called an enum Short for enumeration, this structure is
essentially a wrapper for a group of built-in constants It is more of a way to categorize constants than
to do anything with them You won’t actually use the enum to do anything; rather, you’ll use the stants declared in the enum instead of using their intrinsic values As you can imagine, Access has anumerous built-in enums The following enum describes the constants that can be used to specify theview of a form
con-Enum acFormViewacNormal = 0acDesign = 1acPreview = 2acFormDS = 3acFormPivotTable = 4acFormPivotChart = 5acFormLayout = 6End Enum
You can browse any of the Access or VBA enums in the Object Browser, which you learned about inChapter 4
Trang 38Summar y
In this chapter, you reviewed the basics of VBA and reinforced some of the items covered in Chapter 4
So now you have the basic tools and are ready to start writing code As you proceed through the book,you’ll learn about DAO and ADO, about leveraging the powerful tools that Access provides for cus-tomizing forms and reports, and about interfacing with other programs and applications
Remember that this is a multipurpose reference book It’s a great tool for becoming familiar with mental concepts, as well as for learning about advanced techniques
Trang 39funda-Using DAO to Access Data
As you’ve seen in previous chapters, VBA is the programming language you use to cally interact with the Access object model You use VBA to manipulate Access-specific objects,such as forms, reports, and so on But because Access is a Relational Database ManagementSystem, you will undoubtedly find yourself also needing to programmatically interact with thedata it contains, and indeed with the database design, or schema Microsoft Access employs twodata access object models: Data Access Objects (DAO) and ActiveX Data Objects (ADO)
programmati-Chapter 7 covers ADO; this chapter is solely concerned with the DAO model It begins with a briefhistory of DAO and an indication of when it might be most appropriate to use DAO in preference
to ADO You’ll see the new features in DAO before examining the three most important objects inthe DAO object hierarchy: the DBEngine, Workspace, and Databaseobjects Then you’ll exploredatabase properties and how to use them
Before you start working with DAO objects to access your data, you’ll take an in-depth look athow to use DAO to create and modify your database structure, including tables, fields, indexes,and relations You’ll also spend some time looking at the Access Database Engine (formerly JET
or Joint Engine Technology) security model, and how you can create and manipulate securityobjects, such as users, groups, and of course, how to read and assign object permissions Finally,you’ll look at data access in detail using QueryDefsand Recordsets
Data Access Objects
DAO is the programmatic interface between VBA and Access database engine databases, ODBC(Open Database Connectivity) data stores, and installable ISAM (Indexed Sequential Access Method)data sources, such as Excel, Paradox, dBase, and Lotus 1-2-3.DAO was first released as a part ofVisual Basic 2.0 and later released with Access 1.0 in November 1992 Over the years, many changeshave been made to both DAO and to the Microsoft Jet database engine to reflect technologies at thetime Support for 32-bit operating systems, ODBC data sources, and Unicode languages were allincluded in current versions of DAO
DAO 12.0 is the latest version, shipped with Access 2007, and is the version used by the newACCDB file format This new release was written for use with the Access database engine, which
Trang 40is an updated version of the Microsoft Jet database engine and is 100% compatible with Jet The new tures added to DAO and the Access database engine include new objects and properties that supportmulti-value lookup fields, a new Attachment data type, append-only memo fields, and database encryp-tion using the database password The filename for the Access database engine is ACECORE.DLL (WithACE in the name, you may occasionally see the Access database engine referred to as ACE in news-groups and blogs.)
fea-Why Use DAO?
Visual Basic programmers highly recommend ADO as their preferred object model for accessing bases Although ADO is an excellent model with its own unique benefits, in the context of Access data-bases, it doesn’t have the benefit of native database connectivity, which is where DAO has the distinctadvantage
data-Applications written in other programming languages, such as Visual Basic, Delphi, and the like, mustexplicitly connect to the data source they intend to manipulate, and they must do so every time theyneed to manipulate the data or underlying schema That’s because, unlike Access, these applications donot have an inherent connection to the data source When used in Access, DAO enables you to manipu-late data and schema through an implicit connection that Access maintains to whichever Access data-base engine, ODBC, or ISAM data source it happens to be connected to
Because linked tables are a uniquely Access-specific feature, DAO is quite simply the better alternative foraccessing Access databases In fact, it is impossible to do so natively using any other data access model.DAO has evolved right alongside Jet and the Access database engine, and has become the best model foraccessing and manipulating Access database engine objects and structure Because of its tight integrationwith Access, DAO also provides much faster access to Access databases than does ADO or the JetReplication Objects (JRO) This may all sound like marketing hype, but to qualify the advantages ofDAO over other models, consider the following:
❑ ADO connections can only be applied to one database at a time, whereas DAO enables you tolink (connect) to multiple databases simultaneously
❑ Using the OpenRecordsetmethod’s dbDenyWriteoption, DAO enables you to open a tablewhile preventing other users from opening the same table with write access The ADOConnectionobject’s adModeShareDenyWriteconstant operates at connection level — not attable level
❑ Using the OpenRecordsetmethod’s dbDenyReadoption, DAO enables you to open a tablewhile preventing other users from opening the table at all The ADO Connection object’sadModeShareDenyReadconstant can only be set at connection level
❑ You can create users and groups in DAO, but not in ADO, because you can’t specify the PID(Personal IDentifier) in ADO
❑ You can secure Access objects (such as forms, reports, and so on) in DAO, but not in ADO,because there are no suitable ADO constants to specify permissions for execute, read changes,and write changes
❑ You can dynamically link an updatable ODBC table in DAO, but not in ADO