Variables in Visual Basic 6
Variables in Visual Basic 6
com/learn-vb6
Variables are the memory locations which are used to store values temporarily. A defined
naming strategy has to be followed while naming a variable. A variable name must begin with an
alphabet letter and should not exceed 255 characters. It must be unique within the same scope. It
should not contain any special character like %, &, !, #, @ or $.
There are many ways of declaring variables in Visual Basic. Depending on where the variables
are declared and how they are declared, we can determine how they can be used by our
application. The different ways of declaring variables in Visual Basic are listed below and
elucidated in this section.
Explicit Declaration
Using Option Explicit statement
Scope of Variables
Explicit Declaration
Declaring a variable tells Visual Basic to reserve space in memory. It is not must that a variable
should be declared before using it. Automatically whenever Visual Basic encounters a new
variable, it assigns the default variable type and value. This is called implicit declaration. Though
this type of declaration is easier for the user, to have more control over the variables, it is
advisable to declare them explicitly. The variables are declared with a Dim statement to name the
variable and its type. The As type clause in the Dim statement allows to define the data type or
object type of the variable. This is called explicit declaration.
Syntax
For example,
Intcount = Intcount + 1
This calculation will result in intcount yielding a value of 1 as intcount would have been
initialized to zero. This is because the intcount variable has been mityped as incont in the right
hand side of the second variable. But Visual Basic does not see this as a mistake and considers it
to be new variable and therefore gives a wrong result.
In Visual Basic, to prevent errors of this nature, we can declare a variable by adding the
following statement to the general declaration section of the Form.
Option Explicit
This forces the user to declare all the variables. The Option Explicit statement checks in the
module for usage of any undeclared variables and reports an error to the user. The user can thus
rectify the error on seeing this error message.
The Option Explicit statement can be explicitly placed in the general declaration section of each
module using the following steps.
Scope of variables
A variable is scoped to a procedure-level (local) or module-level variable depending on how it is
declared. The scope of a variable, procedure or object determines which part of the code in our
application are aware of the variable's existence. A variable is declared in general declaration
section of e Form, and hence is available to all the procedures. Local variables are recognized
only in the procedure in which they are declared. They can be declared with Dim and Static
keywords. If we want a variable to be available to all of the procedures within the same module,
or to all the procedures in an application, a variable is declared with broader scope.
Local Variables
A local variable is one that is declared inside a procedure. This variable is only available to the
code inside the procedure and can be declared using the Dim statements as given below.
The local variables exist as long as the procedure in which they are declared, is executing. Once
a procedure is executed, the values of its local variables are lost and the memory used by these
variables is freed and can be reclaimed. Variables that are declared with keyword Dim exist only
as long as the procedure is being executed.
Static Variables
Static variables are not reinitialized each time Visual Invokes a procedure and therefore retains
or preserves value even when a procedure ends. In case we need to keep track of the number of
times a command button in an application is clicked, a static counter variable has to be declared.
These static variables are also ideal for making controls alternately visible or invisible. A static
variable is declared as given below.
Variables have a lifetime in addition to scope. The values in a module-level and public variables
are preserved for the lifetime of an application whereas local variables declared with Dim exist
only while the procedure in which they are declared is still being executed. The value of a local
variable can be preserved using the Static keyword. The follwoing procedure calculates the
running total by adding new values to the previous values stored in the static variable value.
Function RunningTotal ( )
Static Accumulate
Accumulate = Accumulate + num
RunningTotal = Accumulate
End Function
If the variable Accumulate was declared with Dim instead of static, the previously accumulated
values would not be preserved accross calls to the procedure, and the procedure would return the
same value with which it was called. To make all variables in a procedure static, the Static
keyword is placed at the beginning of the procedure heading as given in the below statement.
Example
The following is an example of an event procedure for a CommandButton that counts and
displays the number of clicks made.
The first time we click the CommandButton, the Counter starts with its default value of zero.
Visual Basic then adds 1 to it and prints the result.
A module level variable is available to all the procedures in the module. They are declared using
the Public or the Private keyword. If you declare a variable using a Private or a Dim statement in
the declaration section of a module—a standard BAS module, a form module, a class module,
and so on—you're creating a private module-level variable. Such variables are visible only from
within the module they belong to and can't be accessed from the outside. In general, these
variables are useful for sharing data among procedures in the same module:
You can also use the Public attribute for module-level variables, for all module types except
BAS modules. (Public variables in BAS modules are global variables.) In this case, you're
creating a strange beast: a Public module-level variable that can be accessed by all procedures in
the module to share data and that also can be accessed from outside the module. In this case,
however, it's more appropriate to describe such a variable as a property:
You can access a module property as a regular variable from inside the module and as a custom
property from the outside:
The lifetime of a module-level variable coincides with the lifetime of the module itself. Private
variables in standard BAS modules live for the entire life of the application, even if they can be
accessed only while Visual Basic is executing code in that module. Variables in form and class
modules exist only when that module is loaded in memory. In other words, while a form is active
(but not necessarily visible to the user) all its variables take some memory, and this memory is
released only when the form is completely unloaded from memory. The next time the form is re-
created, Visual Basic reallocates memory for all variables and resets them to their default values
(0 for numeric values, "" for strings, Nothing for object variables).
A variable can have the same name and different scope. For example, we can have a public
variable named R and within a procedure we can declare a local variable R. References to the
name R within the procedure would access the local variable and references to R outside the
procedure would access the public variable.
Related Topics
Visual Basic uses building blocks such as Variables, Data Types, Procedures, Functions and
Control Structures in its programming environment. This section concentrates on the
programming fundamentals of Visual Basic with the blocks specified.
Modules
Code in Visual Basic is stored in the form of modules. The three kind of modules are Form
Modules, Standard Modules and Class Modules. A simple application may contain a single
Form, and the code resides in that Form module itself. As the application grows, additional
Forms are added and there may be a common code to be executed in several Forms. To avoid the
duplication of code, a separate module containing a procedure is created that implements the
common code. This is a standard Module.
Class module (.CLS filename extension) are the foundation of the object oriented programming
in Visual Basic. New objects can be created by writing code in class modules. Each module can
contain:
Declarations : May include constant, type, variable and DLL procedure declarations.
Procedures : A sub function, or property procedure that contain pieces of code that can be
executed as a unit.
These are the rules to follow when naming elements in VB - variables, constants, controls,
procedures, and so on:
1. Numeric
2. String
Use to store alphanumeric values. A variable length string can store approximately 4 billion
characters
3. Date
Use to store date and time values. A variable declared as date type can store both date and time
values and it can store date values 01/01/0100 up to 12/31/9999
4. Boolean
Boolean data types hold either a true or false value. These are not stored as numeric values and
cannot be used as such. Values are internally stored as -1 (True) and 0 (False) and any non-zero
value is considered as true.
5. Variant
Stores any type of data and is the default Visual Basic data type. In Visual Basic if we declare a
variable without any data type by default the data type is assigned as default.
Relational Operators
Operators Description Example Result
> Greater than 10>8 True
< Less than 10<8 False
>= Greater than or equal to 20>=10 True
<= Less than or equal to 10<=20 True
<> Not Equal to 5<>4 True
= Equal to 5=7 False
Logical Operators
Operators Description
OR Operation will be true if either of the operands is true
AND Operation will be true only if both the operands are true
Related Topics
It is easier to debug a program a program with procedures, which breaks a program into discrete
logical limits.
Procedures used in one program can act as building blocks for other programs with slight
modifications.
Sub Procedures
A sub procedure can be placed in standard, class and form modules. Each time the procedure is
called, the statements between Sub and End Sub are executed. The syntax for a sub procedure is
as follows:
arglist is a list of argument names separated by commas. Each argument acts like a variable in
the procedure. There are two types of Sub Procedures namely general procedures and event
procedures.
Event Procedures
An event procedure is a procedure block that contains the control's actual name, an
underscore(_), and the event name. The following syntax represents the event procedure for a
Form_Load event.
General Procedures
A general procedure is declared when several event procedures perform the same actions. It is a
good programming practice to write common statements in a separate procedure (general
procedure) and then call them in the event procedure.
The Code window is opened for the module to which the procedure is to be added.
The Add Procedure option is chosen from the Tools menu, which opens an Add
Procedure dialog box as shown in the figure given below.
The name of the procedure is typed in the Name textbox
Under Type, Sub is selected to create a Sub procedure, Function to create a Function
procedure or Property to create a Property procedure.
Under Scope, Public is selected to create a procedure that can be invoked outside the
module, or Private to create a procedure that can be invoked only from within the
module.
We can also create a new procedure in the current module by typing Sub ProcedureName,
Function ProcedureName, or Property ProcedureName in the Code window. A Function
procedure returns a value and a Sub Procedure does not return a value.
Function Procedures
Functions are like sub procedures, except they return a value to the calling procedure. They are
especially useful for taking one or more pieces of data, called arguments and performing some
tasks with them. Then the functions returns a value that indicates the results of the tasks
complete within the function.
The following function procedure calculates the third side or hypotenuse of a right triangle,
where A and B are the other two sides. It takes two arguments A and B (of data type Double) and
finally returns the results.
The above function procedure is written in the general declarations section of the Code window.
A function can also be written by selecting the Add Procedure dialog box from the Tools menu
and by choosing the required scope and type.
Property Procedures
A property procedure is used to create and manipulate custom properties. It is used to create read
only properties for Forms, Standard modules and Class modules.Visual Basic provides three kind
of property procedures-Property Let procedure that sets the value of a property, Property Get
procedure that returns the value of a property, and Property Set procedure that sets the references
to an object.
Related Topics
VB6 Data Types, Modules and Operators
Variables in Visual Basic 6
Control Structures in VB6 - If...Then...Else Statement, Select...Case Statement
Loops in Visual Basic 6
Arrays in Visual Basic 6
Control Statements are used to control the flow of program's execution. Visual Basic supports
control structures such as if... Then, if...Then ...Else, Select...Case, and Loop structures such as
Do While...Loop, While...Wend, For...Next etc method.
If <condition> Then
statement
End If
Method 1
Method 2
e.g.: Assume you have to find the grade using nested if and display in a text box
e.g.: Assume you have to find the grade using select...case and display in the text box
average = txtAverage.Text
Select Case average
Case 100 To 75
txtGrade.Text ="A"
Case 74 To 65
txtGrade.Text ="B"
Case 64 To 55
txtGrade.Text ="C"
Case 54 To 45
txtGrade.Text ="S"
Case 44 To 0
txtGrade.Text ="F"
Case Else
MsgBox "Invalid average marks"
End Select
Note: In this example I have used a message box function. In later lessons you will learn how to
use message box functions.
Related Topics
A variable number is initialized to 1 and then the Do While Loop starts. First, the condition is
tested; if condition is True, then the statements are executed. When it gets to the Loop it goes
back to the Do and tests condition again. If condition is False on the first pass, the statements are
never executed.
number = 1
While number <=100
number = number + 1
Wend
Do Until...Loop Statement
Unlike the Do While...Loop and While...Wend repetition structures, the Do Until... Loop
structure tests a condition for falsity. Statements in the body of a Do Until...Loop are executed
repeatedly as long as the loop-continuation test evaluates to False.
An example for Do Until...Loop statement. The coding is typed inside the click event of the
command button
Numbers between 1 to 1000 will be displayed on the form as soon as you click on the command
button.
Dim x As Integer
For x = 1 To 50
Print x
Next
In order to count the numbers from 1 yo 50 in steps of 2, the following loop can be used
For x = 1 To 50 Step 2
Print x
Next
The above coding will display numbers vertically on the form. In order to display numbers
horizontally the following method can be used.
For x = 1 To 50
Print x & Space$ (2);
Next
To increase the space between the numbers increase the value inside the brackets after the &
Space$.
Following example is a For...Next repetition structure which is with the If condition used.
In the output instead of number 4 you will get the "This is number 4".
Related Topics
If <condition> Then
statement
End If
Method 1
Method 2
e.g.: Assume you have to find the grade using nested if and display in a text box
e.g.: Assume you have to find the grade using select...case and display in the text box
average = txtAverage.Text
Select Case average
Case 100 To 75
txtGrade.Text ="A"
Case 74 To 65
txtGrade.Text ="B"
Case 64 To 55
txtGrade.Text ="C"
Case 54 To 45
txtGrade.Text ="S"
Case 44 To 0
txtGrade.Text ="F"
Case Else
MsgBox "Invalid average marks"
End Select
Note: In this example I have used a message box function. In later lessons you will learn how to
use message box functions.
Related Topics
A For...Next loop condition can be terminated by an Exit For statement. Consider the following
statement block.
Dim x As Integer
For x = 1 To 10
Print x
If x = 5 Then
Print "The program exited at x=5"
Exit For
End If
Next
The preceding code increments the value of x by 1 until it reaches the condition x = 5. The Exit
For statement is executed and it terminates the For...Next loop. The Following statement block
containing Do...While loop is terminated using Exit Do statement.
Dim x As Integer
Do While x < 10
Print x
x=x+1
If x = 5 Then
Print "The program is exited at x=5"
Exit Do
End If
Loop
With Text1
.Font.Size = 14
.Font.Bold = True
.ForeColor = vbRed
.Height = 230
.Text = "Hello World"
End With
In the above coding, the object Text1, which is a text box is evaluated only once instead of every
associated property or method. This makes the coding simpler and efficient.
Related Topics
Not only does Visual Basic let you store date and time information in the specific Date data type,
it also provides a lot of date- and time-related functions. These functions are very important in all
business applications and deserve an in-depth look. Date and Time are internally stored as
numbers in Visual Basic. The decimal points represents the time between 0:00:00 and 23:59:59
hours inclusive.
The system's current date and time can be retrieved using the Now, Date and Time functions in
Visual Basic. The Now function retrieves the date and time, while Date function retrieves only
date and Time function retrieves only the time.
To display both the date and time together a message box is displayed use the statement given
below.
MsgBox "The current date and time of the system is" & Now
Here & is used as a concatenation operator to concentrate the string and the Now function.
Selective portions of the date and time value can be extracted using the below listed functions.
The calculation and conversion functions related to date and time functions are listed below.
Function Description
DateAdd ( ) Returns a date to which a specific interval has been added
DateDiff ( ) Returns a Long data type value specifying the interval between
the two values
DatePart ( ) Returns an Integer containing the specified part of a given date
DateValue ( ) Converts a string to a Date
TimeValue ( ) Converts a string to a time
DateSerial ( ) Returns a date for specified year, month and day
DateDiff Function
The DateDiff function returns the intervals between two dates in terms of years, months or days.
The syntax for this is given below.
DateDiff (interval, date1, date2[, firstdayofweek[, firstweekofyear]])
Format Function
The format function accepts a numeric value and converts it to a string in the format specified by
the format argument. The syntax for this is given below.
Part Description
Expression Required any valid expression
format Optional. A valid named or user-defined format expression.
firstdayofweek Optional. A contant that specifies the first day of the week.
firstweekofyear Optional. A contant that specifies the first week of the year
Print Date & " " & Time ' Displays "8/14/98 8:35:48 P.M.".
' Set a new system date using any valid date format.
Date = "10/14/98"
Date = "October 14, 1998"
To help you compare the outcome of all date and time functions, all the examples in this section
assume that they're executed at the date and time shown in the preceding code snippet: October
17, 2008, 9:25:33 p.m.
The outdated Date$ and Time$ properties can also be used for the same task. They're String
properties, however, and therefore recognize only the mm/dd/yy or mm/dd/yyyy formats and the
hh:mm:ss and hh:mm formats, respectively. For this reason, it's usually better to use the new $-
less functions.
The Now function returns a Date value that contains the current date and time:
But the time-honored Timer function returns the number of seconds elapsed from midnight and
is more accurate than Now because the Timer function includes fractional parts of seconds. (The
actual accuracy depends on the system.) This function is often used for benchmarking a portion
of code:
StartTime = Timer
' Insert the code to be benchmarked here.
Print Timer - StartTime
The preceding code suffers from some inaccuracy: The StartTime variable might be assigned
when the system tick is about to expire, so your routine could appear to take longer than it
actually does. Here's a slightly better approach:
StartTime = NextTimerTick
' Insert the code to be benchmarked here.
Print Timer _ StartTime
The bug manifests itself very rarely—for example, if the program asks for a 2-second pause at
11:59:59 p.m. Even if this probability is small, the effect of this minor bug is devastating and
you'll have to press Ctrl+Alt+Del to kill your compiled application. Here's a way to work around
this issue:
There are many ways to assemble a Date value. For example, you can use a Date constant, such
as the following:
but more often you'll build a Date value using one of the many functions that VBA gives you.
The DateSerial function builds a Date value from its year/month/day components; similarly, the
TimeSerial function builds a Time value from its hour/minute/second components:
The DateSerial function is also useful for determining indirectly whether a particular year is a
leap year:
The DateValue and TimeValue functions return the date or time portions of their argument,
which can be a string or a Date expression:
A bunch of VBA functions let you extract date and time information from a Date expression or
variable. The Day, Month, and Year functions return date values, whereas the Hour, Minute, and
Second functions return time values:
The Weekday function returns a number in the range 1 through 7, which corresponds to the day
of the week of a given Date argument:
Although using the optional second argument forces the function to return the correct value, it
doesn't change the system localization. If you next call the Weekday function without the second
argument, it will still consider the first day of the week to be what it was before.
Finally you can extract any date and time information from a Date value or expression using the
DatePart function, for which the syntax is
You'll rarely need to resort to this function because you can do most of your calculations using
the other functions I've shown you so far. In two cases, however, this function is really useful:
The first argument can be one of the String constants listed in the following table. For more
information about the two optional arguments, see the description of the DateAdd function in the
next section.
Possible values for the interval argument in DatePart, DateAdd, and DateDiff functions.
Setting Description
"yyyy" Year
"q" Quarter
"m" Month
"y" Day of the year (same as d)
"d" Day
"w" Weekday
"ww" Week
"h" Hour
"n" Minute
"s" Second
More on Date and Time in Visual Basic 6
For more sophisticated date math, you can use the DateAdd function, for which the syntax is the
following:
The interval is a string that indicates a date or time unit (see table below), number is the number
of units you are adding, and date is the starting date. You can use this function to add and
subtract date and time values:
When you have two dates and you want to evaluate the difference between them—that is, the
time elapsed between one date and the next—you should use the DateDiff function, for which
the syntax is
Result = DateDiff(interval, startdate, enddate _
[, FirstDayOfWeek[, FirstWeekOfYear]])
where interval has the meaning shown in the previous page Building and Extracting Date and
Time Values's table, FirstDayOfWeek is an optional argument that you can use to specify which
weekday should be considered as the first day of the week (you can use the constants vbSunday,
vbMonday, and so on), and FirstWeekOfYear is another optional argument that lets you specify
which week should be considered as the first week of the year.
General Date (date and time in general format; only the date if the fractional part is 0;
only the time if the integer part is 0)
Long Date (for example, Friday, October 17, 2008, but results vary depending on your
locale)
Medium Date (for example, 17-Oct-2008)
Short Date (for example, 10/17/2008)
Long Time (for example, 8:35:48)
Medium Time (for example, 8:35 A.M.)
Short Time (for example, 8:35 in a 24 hour format)
You also have a few special characters with which you can build your own custom date and time
format strings, including one- and two-digit day and month numbers, complete or abbreviated
month and weekday names, a.m/p.m. indicators, week and quarter numbers, and so on:
Visual Basic 6 has introduced the new FormatDateTime function. It's far less flexible than the
standard Format function and permits only a subset of the Format function's named formats. The
only advantage of the FormatDateTime function is that it's also supported under VBScript and so
can contribute to the ease of porting pieces of code from Visual Basic and VBA to VBScript and
vice versa. Its syntax is
where NamedFormat can be one of the following intrinsic constants: 0-vbGeneralDate (the
default), 1-vbLongDate, 2-vbShortDate, 3-vbLongTime, or 4-vbShortTime. Here are a few
examples:
Visual Basic 6 also includes two new functions related to date formatting. The MonthName
function returns the complete or abbreviated name of a month, whereas the WeekdayName
function returns the complete or abbreviated name of a weekday. Both are locale aware, so you
can use them to list month and weekday names in the language the operating system has been
configured for:
An array is a consecutive group of memory locations that all have the same name and the same
type. To refer to a particular location or element in the array, we specify the array name and the
array element position number.
The Individual elements of an array are identified using an index. Arrays have upper and lower
bounds and the elements have to lie within those bounds. Each index number in an array is
allocated individual memory space and therefore users must evade declaring arrays of larger size
than required. We can declare an array of any of the basic data types including variant, user-
defined types and object variables. The individual elements of an array are all of the same data
type.
Declaring arrays
Arrays occupy space in memory. The programmer specifies the array type and the number of
elements required by the array so that the compiler may reserve the appropriate amount of
memory. Arrays may be declared as Public (in a code module), module or local. Module arrays
are declared in the general declarations using keyword Dim or Private. Local arrays are declared
in a procedure using Dim or Static. Array must be declared explicitly with keyword "As".
Fixed-size array : The size of array always remains the same-size doesn't change during the
program execution.
Dynamic array : The size of the array can be changed at the run time- size changes during the
program execution.
Fixed-sized Arrays
When an upper bound is specified in the declaration, a Fixed-array is created. The upper limit
should always be within the range of long data type.
Declaring a fixed-array
In the above illustration, numbers is the name of the array, and the number 6 included in the
parentheses is the upper limit of the array. The above declaration creates an array with 6
elements, with index numbers running from 0 to 5.
If we want to specify the lower limit, then the parentheses should include both the lower and
upper limit along with the To keyword. An example for this is given below.
In the above statement, an array of 10 elements is declared but with indexes running from 1 to 6.
A public array can be declared using the keyword Public instead of Dim as shown below.
Multidimensional Arrays
Arrays can have multiple dimensions. A common use of multidimensional arrays is to represent
tables of values consisting of information arranged in rows and columns. To identify a particular
table element, we must specify two indexes: The first (by convention) identifies the element's
row and the second (by convention) identifies the element's column.
Tables or arrays that require two indexes to identify a particular element are called two
dimensional arrays. Note that multidimensional arrays can have more than two dimensions.
Visual Basic supports at least 60 array dimensions, but most people will need to use more than
two or three dimensional-arrays.
It is also possible to define the lower limits for one or both the dimensions as for fixed size
arrays. An example for this is given here.
An example for three dimensional-array with defined lower limits is given below.
Visual Basic starts indexing the array with 0. Therefore, the preceding array actually holds 101
items.
Most programs don't use static arrays because programmers rarely know at compile time how
many items you need and also because static arrays can't be resized during execution. Both these
issues are solved by dynamic arrays. You declare and create dynamic arrays in two distinct steps.
In general, you declare the array to account for its visibility (for example, at the beginning of a
module if you want to make it visible by all the procedures of the module) using a Dim
command with an empty pair of brackets. Then you create the array when you actually need it,
using a ReDim statement:
Sub PrintReport()
' This array is visible only to the procedure.
ReDim Customers(1000) As String
' ...
End Sub
If you don't specify the lower index of an array, Visual Basic assumes it to be 0, unless an Option
Base 1 statement is placed at the beginning of the module. My suggestion is this: Never use an
Option Base statement because it makes code reuse more difficult. (You can't cut and paste
routines without worrying about the current Option Base.) If you want to explicitly use a lower
index different from 0, use this syntax instead:
Dynamic arrays can be re-created at will, each time with a different number of items. When you
re-create a dynamic array, its contents are reset to 0 (or to an empty string) and you lose the data
it contains. If you want to resize an array without losing its contents, use the ReDim Preserve
command:
When you're resizing an array, you can't change the number of its dimensions nor the type of the
values it contains. Moreover, when you're using ReDim Preserve on a multidimensional array,
you can resize only its last dimension:
Finally, you can destroy an array using the Erase statement. If the array is dynamic, Visual Basic
releases the memory allocated for its elements (and you can't read or write them any longer); if
the array is static, its elements are set to 0 or to empty strings.
You can use the LBound and UBound functions to retrieve the lower and upper indices. If the
array has two or more dimensions, you need to pass a second argument to these functions to
specify the dimension you need:
Type MyUDT
StaticArr(100) As Long
DynamicArr() As Long
End Type
...
Dim udt As MyUDT
' You must DIMension the dynamic array before using it.
ReDim udt.DynamicArr(100) As Long
' You don't have to do that with static arrays.
udt.StaticArr(1) = 1234
The memory needed by a static array is allocated within the UDT structure; for example, the
StaticArr array in the preceding code snippet takes exactly 400 bytes. Conversely, a dynamic
array in a UDT takes only 4 bytes, which form a pointer to the memory area where the actual
data is stored. Dynamic arrays are advantageous when each individual UDT variable might host
a different number of array items. As with all dynamic arrays, if you don't dimension a dynamic
array within a UDT before accessing its items, you get an error 9—"Subscript out of range."
See Also
Visual Basic lets you store arrays in Variant variables and then access the array items using the
Variant variable as if it were an array:
You can even create an array of Variant elements on the fly using the Array function and store it
in a Variant variable:
Likewise, you can pass an array to a procedure that expects a Variant parameter and then access
the elements of the array through that parameter:
The most interesting feature of the preceding routine is that it works correctly with any type of
numeric one-dimensional array. It even works with String arrays, but in that case you get the
concatenation of all items, not their sum. This procedure is extremely powerful and reduces the
amount of code you have to write to deal with different kinds of arrays. But you should be aware
that accessing array items through a Variant parameter noticeably slows down the execution. If
you need the best performance, write specific routines that process specific types of arrays.
You can also pass a multidimensional array to a routine that expects a Variant parameter. In this
case, you can still access the array elements through the Variants, but if you don't know at
compile time how many dimensions the array has, your routine has to determine that number
before proceeding. You can get this value using a trial-and-error approach:
It's perfectly legal to use the function name inside a function's code as if it were a local variable,
as the previous code snippet does. Often this technique lets you save a local variable and a final
assignment before exiting the routine, which indirectly makes your code run slightly faster.
Here's a modified ArraySum routine that uses NumberOfDims and works with both one- and
two-dimensional arrays:
Often, if a Variant contains an array, you don't know the basic type of that array in advance. The
VarType function returns the sum of the vbArray constant (decimal 8192), plus the VarType of
the data included in the array. This lets you test that the array passed to a routine is of a given
type:
You can also test whether a Variant holds an array using the IsArray function. When a Variant
variable holds an array, the TypeName function appends a pair of empty parentheses to its result:
As I've explained, you can either assign an array to a Variant variable or you can pass an array as
a Variant parameter of a procedure. While the two operations look very similar, they're
substantially different. To execute an assignment, Visual Basic makes a physical copy of the
array. As a result, the Variant variable doesn't point to the original data but to the copy; from this
point on, all the manipulations you do through the Variant variable don't affect the original array.
Conversely, if you call a procedure and pass an array as a Variant parameter, no data is
physically copied and the Variant simply works as an alias of the array. You can reorder array
items or modify their values, and your changes are immediately reflected in the original array
See Also
Visual Basic 6 adds two important features to arrays. First, you can perform assignments
between arrays. Second, you can write procedures that return arrays. You can assign arrays only
of the same type and only if the target is a dynamic array. (The latter condition is necessary
because Visual Basic might need to resize the target array.)
It's no surprise that native assignment commands are always faster than the corresponding For…
Next loops that copy one item at a time. The actual increment in speed heavily depends on the
data type of the arrays and can vary from 20 percent to 10 times faster. A native assignment
between arrays also works if the source array is held in a Variant. Under Visual Basic 4 and 5,
you could store an array in a Variant, but you couldn't do the opposite—that is, retrieve an array
stored in a Variant variable and store it back in an array of a specific type. This flaw has been
fixed in Visual Basic 6:
The new capability of returning arrays lets you write highly versatile array routines. Visual Basic
6 itself includes a few new string functions—namely Join, Split, and Filter—that rely on it.
(You'll find more about these new string functions in Chapter 5). Here are two examples of what
you can do with this intriguing feature:
See Also
Byte arrays are somewhat special because Visual Basic lets you directly assign strings to them.
In this case, Visual Basic performs a direct memory copy of the contents of the string. Because
all Visual Basic 5 and 6 strings are Unicode strings (two bytes per character), the target array is
redimensioned to account for the actual string length in bytes (which you can determine using
the LenB function). If the string contains only characters whose code is in the range 0 through
255 (the case if you work with Latin alphabets), every other byte in the array will be 0:
This special treatment reserved for Byte arrays is meant to ease the conversion from old Visual
Basic 3 applications that use strings to hold binary data, as I explained in "The Byte Data Type"
section, earlier in this chapter. You can exploit this feature to create blindingly fast string
routines when you have to process each individual character in a string. For example, see how
quickly you can count all the spaces in a string:
' NOTE: this function might not work with non-Latin alphabets.
Function CountSpaces(Text As String) As Long
Dim b() As Byte, i As Long
b() = Text
For i = 0 To UBound(b) Step 2
' Consider only even-numbered items.
' Save time and code using the function name as a local variable.
If b(i) = 32 Then CountSpaces = CountSpaces + 1
Next
End Function
The preceding routine is about three times faster than a regular routine, which uses Asc and
Mid$ functions to process all the characters in the argument, and even faster if you turn on the
Remove Array Bounds Check compiler optimization. The only drawback of this technique is that
it isn't Unicode-friendly because it considers only the least significant byte in each 2-byte
character. If you plan to convert your application to some language that relies on Unicode—
Japanese, for example—you should stay clear of this optimization technique.
See Also
Some of the most common operations you perform on arrays are inserting and deleting items,
shifting all the remaining elements toward higher indices to make room or toward lower indices
to fill the "hole" a deletion has left. You usually do this with a For…Next loop, and you can even
write generic array procedures that work with any type of array (with the usual restrictions about
arrays of UDTs and fixed-length strings that can't be passed to a Variant parameter):
If your application works intensively with arrays, you might find that an approach based on
For…Next loops is too slow. In some cases, you can considerably speed up these operations by
using the RtlMoveMemory API function, which many Visual Basic programmers know under its
popular alias name, CopyMemory.1 This function lets you move a block of bytes from one
memory address to another memory address and works correctly even if the two areas partially
overlap. Here's the code that inserts a new item in an array of Longs:
IMPORTANT NOTE: The prerequisite for using the CopyMemory API function is that data
must be stored in contiguous memory locations, so you absolutely can't use it to insert or remove
elements in String and Object arrays, nor in arrays of UDTs that contain conventional strings,
object references, or dynamic arrays. (Fixed-length strings and static arrays in UDTs are OK,
though.)
Note that while you can't use the preceding routines for arrays other than Long arrays, the
statements in the procedure body can be recycled for another data type without any change,
thanks to the use of the LenB function. Therefore, you can derive new array functions that work
for other data types by simply modifying the procedure's name and its parameter list. For
example, you can create a new function that deletes an item in a Double array by editing just the
first line of code (shown in boldface):
See Also
Sorting is an operation that you often perform on arrays. As you probably know, there are dozens
of different sort algorithms, each one with its strengths and weaknesses. I found that the Shell
Sort algorithm works well in most cases, and I've prepared a generic routine that sorts any one-
dimensional array of a data type compatible with the Variant type, either in ascending or
descending order:
See Also
The technique is conceptually simple: Since you can store an array in a Variant variable, you can
build an array of Variants, where each item holds an array. Each subarray—a row of this pseudo-
array—can hold a different number of elements, and you don't need to use more memory than is
strictly necessary.
Here's an example, based on an imaginary PIM (Personal Information Manager) program. In this
program, you need to keep track of a list of appointments for each day of the year. The simplest
solution would be to use an array in which each row corresponds to a day in the year and each
column to a possible appointment. (For the sake of simplicity, let's assume that each
appointment's data can be held in a string.)
In this example, I kept the code as simple as possible and used an array of Variant arrays. You
could save even more memory if each row of this array were built using an array of a more
specific data type (String, in this case). Note the special syntax used to address an item in an
array of arrays:
Nothing keeps you from extending this concept further, introducing an array of arrays of arrays,
and so on. If you're dealing with arrays in which each row can vary considerably in length, this
approach is going to save you a lot of memory and, in most cases, improve your overall
performance too. A key feature of an array of arrays is that you can process entire rows of your
pseudo-array as if they were single entities. For example, you can swap them, replace them, add
and delete them, and so on.
' Move the January 1st appointments to January 2nd.
apps(2) = apps(1)
apps(1) = Empty
Finally, an important advantage of this technique is that you can add new rows without losing the
current contents of the array. (Remember that you can use ReDim Preserve on regular arrays
only to modify the number of columns, not the number of rows.)
See Also
A control array can be created only at design time, and at the very minimum at least one control
must belong to it. You create a control array following one of these three methods:
You create a control and then assign a numeric, non-negative value to its Index property;
you have thus created a control array with just one element.
You create two controls of the same class and assign them an identical Name property.
Visual Basic shows a dialog box warning you that there's already a control with that
name and asks whether you want to create a control array. Click on the Yes button.
You select a control on the form, press Ctrl+C to copy it to the clipboard, and then press
Ctrl+V to paste a new instance of the control, which has the same Name property as the
original one. Visual Basic shows the warning mentioned in the previous bullet.
Control arrays are one of the most interesting features of the Visual Basic environment, and they
add a lot of flexibility to your programs:
Controls that belong to the same control array share the same set of event procedures; this
often dramatically reduces the amount of code you have to write to respond to a user's
actions.
You can dynamically add new elements to a control array at run time; in other words, you
can effectively create new controls that didn't exist at design time.
Elements of control arrays consume fewer resources than regular controls and tend to
produce smaller executables. Besides, Visual Basic forms can host up to 256 different
control names, but a control array counts as one against this number. In other words,
control arrays let you effectively overcome this limit.
The importance of using control arrays as a means of dynamically creating new controls at run
time is somewhat reduced in Visual Basic 6, which has introduced a new and more powerful
capability.
Don't let the term array lead you to think control array is related to VBA arrays; they're
completely different objects. Control arrays can only be one-dimensional. They don't need to be
dimensioned: Each control you add automatically extends the array. The Index property
identifies the position of each control in the control array it belongs to, but it's possible for a
control array to have holes in the index sequence. The lowest possible value for the Index
property is 0. You reference a control belonging to a control array as you would reference a
standard array item:
Text1(0).Text = ""
The fact that multiple controls can share the same set of event procedures is often in itself a good
reason to create a control array. For example, say that you want to change the background color
of each of your TextBox controls to yellow when it receives the input focus and restore its
background color to white when the user clicks on another field:
Control arrays are especially useful with groups of OptionButton controls because you can
remember which element in the group has been activated by adding one line of code to their
shared Click event. This saves code when the program needs to determine which button is the
active one:
Where object is the name of the control to add or delete from the control array. Index % is the
value of the index in the array. The control array to be added must be an element of the existing
array created at design time with an index value of 0. When a new element of a control array is
loaded, most of the property settings are copied from the lowest existing element in the array.
* Open a Standard EXE project and save the Form as Calculator.frm and save the Project as
Calculater.vbp.
Proper
Object Setting
ty
Calculator
Caption
Form
frmCalcula
Name
tor
Caption 1
CommandBut
Name cmd
ton
Index 0
Caption 2
CommandBut
Name cmd
ton
Index 1
Caption 3
CommandBut
Name cmd
ton
Index 2
CommandBut Caption 4
ton
Name cmd
Index 3
Caption 5
CommandBut
Name cmd
ton
Index 4
Caption 6
CommandBut
Name cmd
ton
Index 5
Caption 7
CommandBut
Name cmd
ton
Index 6
Caption 8
CommandBut
Name cmd
ton
Index 7
Caption 9
CommandBut
Name cmd
ton
Index 8
Caption 0
CommandBut
Name cmd
ton
Index 10
Caption .
CommandBut
Name cmd
ton
Index 11
Caption AC
CommandBut
ton
Name cmdAC
Caption +
CommandBut
ton
Name cmdPlus
Caption -
CommandBut
ton
Name cmdMinus
*
Caption
CommandBut
ton cmdMultipl
Name
y
Caption /
CommandBut
ton
Name cmdDivide
Caption +/-
CommandBut
ton
Name cmdNeg
Name txtDisplay
TextBox
Text ( empty )
Caption =
CommandBut
ton
Name cmdEqual
The following code is entered in the cmd_Click( ) (Control Array) event procedure
Private Sub cmd_Click(Index As Integer)
txtDisplay.Text = txtDisplay.Text & cmd(Index).Caption
'&is the concatenation operator
Current = Val(txtDisplay.Text)
End Sub
The following code is entered in the click events of the cmdPlus, cmdMinus, cmdMultiply,
cmdDevide controls respectively.
To print the result on the text box, the following code is entered in the cmdEqual_Click ( ) event
procedure.
Case "+"
Result = Previous + Current
txtDisplay.Text = Result
Case "-"
Result = Previous - Current
txtDisplay.Text = Result
Case "*"
Result = Previous * Current
txtDisplay.Text = Result
Case "/"
Result = Previous / Current
txtDisplay.Text = Result
End Select
Current = Result
End Sub
Save and run the project. On clicking digits of user's choice and an operator button, the output
appears.
Here you're using the LBound and UBound methods exposed by the control array object, which
is an intermediate object used by Visual Basic to gather all the controls in the array. In general,
you shouldn't use this approach to iterate over all the items in the array because if the array has
holes in the Index sequence an error will be raised. A better way to loop over all the items of a
control array is using the For Each statement:
A third method exposed by the control array object, Count, returns the number of elements it
contains. It can be useful on several occasions (for example, when removing all the controls that
were added dynamically at run time):
' This code assumes that txtField(0) is the only control that was
' created at design time (you can't unload it at run time).
Do While txtFields.Count > 1
Unload txtFields(txtFields.UBound)
Loop
There are some limitations, though: All the items in an array of menu controls must be adjacent
and must belong to the same menu level, and their Index properties must be in ascending order
(even though holes in the sequence are allowed). This set of requirements severely hinders your
ability to create new menu items at run time. In fact, you can create new menu items in well-
defined positions of your menu hierarchy—namely, where you put a menu item with a nonzero
Index value—but you can't create new submenus or new top-level menus.
Now that you have a thorough understanding of how Visual Basic's forms and controls work,
you're ready to dive into the subtleties of the Visual Basic for Applications (VBA) language.
The user defined data type can be declared with a variable using the Dim statement as in any
other variable declaration statement. An array of these user-defined data types can also be
declared. An example to consolidate these two features is given below.
A User-Defined data type can be referenced in an application by using the variable name in the
procedure along with the item name in the Type block. Say, for example if the text property of a
TextBox namely text1 is to be assigned the name of the electronic good, the statement can be
written as given below.
Text1.Text = ElectronicGoods.ProdName
Text1.Text = ElectronicGoods(i).ProdName
User-defined data types can also be passed to procedures to allow many related items as one
argument.
Related Topics
Constants
Constants are named storage locations in memory, the value of which does not change during
program Execution. They remain the same throughout the program execution. When the user
wants to use a value that never changes, a constant can be declared and created. The Const
statement is used to create a constant. Constants can be declared in local, form, module or global
scope and can be public or private as for variables. Constants can be declared as illustrated
below.
For example consider a statement that will set the window state of a form to be maximized.
Form1.Windowstate = 2
Form1.WindowState = vbMaximized
Data Type Conversion
Visual Basic functions either to convert a string into an integer or vice versa and many more
conversion functions. A complete listing of all the conversion functions offered by Visual Basic
is elucidated below.
Conversion To Function
Boolean Cbool
Byte Cbyte
Currency Ccur
Date Cdate
Decimals Cdec
Double CDbl
Integer Cint
Long CLng
Single CSng
String CStr
Variant Cvar
Error CVErr
A conversion function should always be placed at the right hand side of the calculation
statement.
Related Topics
Open a new Standard EXE project and save the Form as Draw.frm and save the Project as
Draw.vbp. Name the caption of the as Drawing. Add command button control and name the
caption of it as Clear
Button value 1 indicates that the left mouse button is clicked. The code written in the
MouseDown event changes the CurrentX and CurrentY to the coordinates where the mouse
button was just clicked.
Run the application. You can notice that when the mouse is clicked and moved in the Form a line
is drawn corresponding to the mouse movement. Following figure illustrates the combined action
of MouseDown and MouseMove.
The program uses two graphics related Visual Basic concepts, the Line method and the CurrentX
and CurrentY properties. Line method is preferred to draw a line in a Form. The following
statement draws a line from the coordinates X = 2500, Y = 2000, X = 5000, Y = 5500
The CurrentX and CurrentY properties are not visible in the properties window of the Form
because it cannot be set at the design time. After using the Line method to draw a line in a Form,
Visual Basic automatically assigns the coordinate of the line's end point to the CurrentX and
CurrentY properties of the Form on which the line is drawn.
MouseMove application
Visual Basic does not generate a MouseMove event for every pixel the mouse moves over and a
limited number of mouse messages are generated per second by the operating environment. The
following application illustrates how often the Form_MouseMove ( ) event is executed.
Open a new standard EXE project and save the form as MouseMove.frm and save the Project as
MouseMOve.vbp. Place a CommandButton control and name the caption as Clear and set the
name as cmdClear.
Save the application and run. You can notice that when the mouse is moved inside the Form,
circles are drwan along the path of the mouse movement as shown in below figure. And also you
can notice the circles are widely spaced when the mouse is moved quickly. Each small circle is
an indication that the MouseMove event occured and the Form_MouseMove ( ) procedure was
executed.