按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
MsgBox cities(1) & Chr(13) & cities(2) & Chr(13) _
& cities(3) & Chr(13) & cities(4) & Chr(13) _
& cities (5) & Chr(13) & cities(6)
End Sub
在FavoriteCities过程开始之前,缺省的索引编号方式改变了,注意,Option Base 1语句是位于
模块窗口Sub语句之上的。该语句告诉VB给数组的第一个成员赋值数字1,而不是缺省的0。
数组cities()声明为带六个成员的字符串类型变量。然后,给数组的每个成员都赋上了值。最后的
语句使用Msgbox函数显示城市清单。当你运行该过程时,城市名称将会出现在分开的行上(参见图
7…1)。你可以改变显示数据的顺序,改变索引号。
图7…1 你可以用Msgbox函数来显示一维数组的成员
5。 运行FavoriteCities过程并且检查结果
6。 修改FavoriteCities过程,让它逆序显示城市名称(从6到1)
技巧7…4 数组成员的初始值
在给数组成员赋值之前,该成员具有缺省值。数字变量的缺省值为0,而字符串变量的缺省值为空
字符串。
5。数组和循环语句
现在要执行一些例如填充数组或显示数组成员的任务了,你在第六章里学过的好些个循环语句(参
见For…Next和For Each …Next循环)就变得非常方便了。现在是时候将你所学到的技巧结合起来
使用了。如何重新编写FavoriteCities过程,让每个城市名称在不同的信息框里显示出来?
下面显示的过程FavoriteCities2将原来过程的最后部分取代为For Each…Next循环:
Sub FavoriteCities2()
'now declare the array
Dim cities(6) As String
Dim city As Variant
'assign the values to array elements
125
… 页面 142…
cities(1) = 〃Baltimore〃
cities(2) = 〃Atlanta〃
cities(3) = 〃Boston〃
cities(4) = 〃Washington〃
cities(5) = 〃New York〃
cities(6) = 〃Trenton〃
'display the list of cities in separate messages
For Each city in cities
MsgBox city
Next
End Sub
注意For Each…Next循环使用的是Variant数据类型的变量city。回想在前面的章节里,For
Each…Next让你在一个集合的所有对象间或者一个数组的所有的成员间循环,并且对每个对象或成
员执行同样的操作。当你运行过程FavoriteCities2时,数组里有几个成员循环就会执行几次。
我们来看一下过程FavoriteCities的另一种变化。在第四章里,你练习了将参数作为变量传递给子
过程和函数。过程FavoriteCities3示范了如何将数组的成员传递给另一个过程。
1。 在当前模块里,输入下述两个过程:
Sub FavoriteCities3()
'now declare the array
Dim cities(6) As String
'assign the values to array elements
cities(1) = 〃Baltimore〃
cities(2) = 〃Atlanta〃
cities(3) = 〃Boston〃
cities(4) = 〃Washington〃
cities(5) = 〃New York〃
cities(6) = 〃Trenton〃
'call another procedure and pass the array as argument
Hallo cities()
End Sub
Sub Hallo (cities() As String)
Dim counter As Integer
For counter = 1 to 6
MsgBox 〃Hello 〃 & cities(counter)
Next
End Sub
过程Hallo的声明里有一个数组类型的参数——cities()。
2。 运行过程FavoriteCities3。将一个子过程的数组成员传递给另一个子过程或者函数过程让你
可以在许多过程里使用相同的数组,而不需要重复的程序代码。
技巧7…5 在过程之间传递数组
当一个数组在一个过程里被声明时,它是局部的,并且是不为其他过程所知的。然而,你可以将局
部数组传递给其它的过程,通过在声明语句里,写上数组名称,并且后面紧跟一对空括号。例如,
语句Hallo cities() 调用一个名叫Hallo的过程,并且将数组cities()传递给它。
这里有个例子,如何将你新学到的关于数组的知识和循环运用到现实生活中。如果你是个狂热的彩
票玩家的话,当你厌倦了选择你的幸运号码,你可以让VB为你选择。下面的过程Lotto使用1到51
的六个数字填充数组:
Sub Lotto()
Const spins = 6
Const minNum = 1
Const maxNum = 51
126
… 页面 143…
Dim t As Integer ‘looping variable in outer loop 外部循环变量
Dim i As Integer ‘looping variable in inner loop 内部循环变量
Dim myNumbers As String ‘string to hold all picks 储存选号的字符串
Dim lucky(spins) As String ‘array to hold generated picks 储存产生的选号的数组
myNumbers = 〃〃
For t = 1 To spins
Randomize
lucky(t) = Int((maxNum…minNum+1) * Rnd )+ minNum)
'see if this number was picked before 检查本数字是否之前被选出来过
For i = 1 To (t…1)
If lucky(t)=lucky(i) Then
lucky(t) = Int((maxNum–minNum+1) * Rnd)+ minNum) i = 0
End If
Next i
MsgBox 〃Lucky number is 〃 & t & lucky(t)
myNumbers = myNumbers & 〃 –〃 & lucky(t)
Next t
MsgBox 〃Lucky numbers are 〃 & myNumbers
End Sub
Randomize语句将随机数字发生器初始化。指令Int((maxNum…minNum+1) * Rnd + minNum)使用函数
Rnd来产生一个在minNum和maxNum之间的随机数值。函数Int将随机数转变为一个整数。除了给
minNum和maxNum赋予常量之外,你也可以使用函数InputBox从用户那里获得数据。
内部For…Next循环确保每个选出的数字是唯一的——它不能是之前选出的任何一个数字。如果你
忽略了内部循环并且多次运行该过程,你很可能看到重复的号码。
6。使用二维数组
既然你已经知道了如何有规划地产生一个清单(一维数组),是时候仔细看一下如何使用数据表了。
下面的过程产生一个二维数组,储存国家名称,货币名称和交换汇率。
Sub Exchange()
Dim t As String
Dim r As String
Dim Ex(3; 3) As Variant
t = Chr(9) 'tab
r = Chr(13) 'Enter
Ex(1; 1) = 〃Japan〃
Ex(1; 2) = 〃Yen〃
Ex(1; 3) = 128。2
Ex(2; 1) = 〃Mexico〃
Ex(2; 2) = 〃Peso〃
Ex(2; 3) = 9。423
Ex(3; 1) = 〃Canada〃
Ex(3; 2) = 〃Dollar〃
Ex(3; 3) = 1。567
MsgBox 〃Country 〃 & t & t & 〃Currency〃 & t & 〃per US〃 _
& r & r _
& Ex(1; 1) & t & t & Ex(1; 2) & t & Ex(1; 3) & r _
& Ex(2; 1) & t & t & Ex(2; 2) & t & Ex(2; 3) & r _
& Ex(3; 1) & t & t & Ex(3; 2) & t & Ex(3; 3); ; _
〃Exchange〃
End Sub
127
… 页面 144…
当你运行过程Exchange时,你将看到一个信息框,显示三列信息(见图7…2)
图7…2 显示在信息框上的文本是可以自定义格式的。
7。静态和动态数组
到目前为止,本章介绍的都是静态数组。静态数组是具有确定大小的数组。当你事先知道数组的大
小时使用静态数组。静态数组的大小是在数组的声明语句里确定的,例如,语句Dim Fruits(10) As
String声明了一个由10个成员组成的叫做Fruits的静态数组。
但是,万一你不肯定你的数组会包含多少个成员呢?如果你的过程由用户输入决定,每次程序执行
时,用户提供的成员数可能会变化的。你如果确保你声明的数组不会浪费内存呢?
回想你声明了一个数组后,VBA会留出足够的内存来储存数组。如果你声明一个比你需要的更多成
员的数组的话,你将浪费计算机资源。这个问题的解决方法是让你的数组变为动态的。动态数组是
大小可以改变的数组。如果数组的大小每次都由程序运行而决定的话,就使用动态数组。
技巧7…6 固定大小的数组
静态数组包含固定成员个数。静态数组的成员个数在它被声明后就再也不能改变了。
要声明动态数组,那么不要在数组名称后面的括号里放置数字:
Dim Fruits( ) As String
动态数组通过在数组名称后面附带空括号来声明。在你使用动态数组于过程里之前,你必须使用
ReDim语句来动态地设置数组的上界和下界。ReDim语句随着程序代码的执行重新设定数组大小,
ReDim语句通知VB数组的新大小,这个语句可以在同一个过程里多次使用。现在,我们来看看如何
使用动态数组。
1。 在当前工程里插入一个新模块并且重新命名为DynamicArrays
2。 输入下列过程DynArray:
Sub DynArray( )
Dim counter As Integer
'declare a dynamic array
Dim myArray( ) As Integer
'specify the initial size of the array
Redim myArray(5)
Workbooks。Add
'populate myArray with values
For counter = 1 to 5
myArray(counter) = counter +1
ActiveCell。Offset(counter…1; 0)。Value = myArray(counter)
Next
'change the size of myArray to hold 10 elements
Redim Preserve myArray(10)
'add new values to myArray
For counter = 6 To 10
myArray(counter) = counter * counter
With ActiveCell。Offset(counter…1; 0)
。Value = myArray(counter)
。Font。Bold = True
128
… 页面 145…
End with
Next counter
End Sub
3。 将你的Excel窗口和VB编辑器窗口并排显示
4。 逐步运行过程DynArray。你可以将鼠标置于代码中间,并且按下F8来执行逐条语句。程序
DynArray的结果如下图所示。
图7…3 显示10个数据的数组
在过程DynArray里,Dim myArray() As Integer语句声明了一个叫做myArray的动态数组。尽管该
语句声明了数组,但是,没有分配任何内存给该数组。第一条ReDim语句明确了myArray的开始大小
并且占据了10个字节的内存让它储存5个成员,正如你所知,每个整型数据需要两个字节的内存。
语句Workbooks。Add打开一新工作簿,然后For…Next循环用数据填充数组myArray并且将数组的成
员写入工作表。在循环开始之前,变量counter等于1。循环里的第一条语句:
myArray(counter) = counter + 1
分配数值2给myArray的第一个成员。第二条语句:
ActiveCell。Offset(counter…1; 0)。Value = myArray(counter)
将myArray成员的值输入到当前单元格里。当前单元格为A1。因为变量counter等于1,所以上面的
语句就等于:
ActiveCell。Offset(1…1; 0)。Value = myArray(1)
或者
ActiveCell。Offset(0;0)。Value = myArray(1)
上面的语句在单元格A1里输入数据。循环里面的语句被执行5次。VB在合适的工作表单元格里马输
入数据并且进行到下一语句:
ReDim Preserve myArray(10)
通常,当你改变一个数组的大小时,你将失去该数组原来的所有数据。语句ReDim将数组重新初始
化。
然而,你可以将新成员加入到现存的数组里去,通过在语句ReDim后面带上关键字Preserve。换句
话说,关键字Preserve保证重新改变大小的数组不会弄丢现有的数据。如果你忽略它,新数组将会
是空的。
第二个For…Next循环给数组myArray的第六,第七,第八,第九和第十个成员赋值。这次,数组成
员的数值是相乘的:counter * counter。VB使用粗体将数组其它的数值输入到合适的工作表的单
元格里面。
技巧7…7 确定数组大小
在使用数组之前,必须在Dim或ReDim语句里确定数组的大小。这意味着你不可以给数组成员赋值,
直到你使用Dim或者ReDim语句声明了该数组。
8。数组函数
你可以通过五个VBA内置函数来操作数组:Array; IsArray; Erase; LBound和UBound。接下来的章
129
… 页面 146…
节将示范每个函数在VBA过程里的使用。
9。Array 函数
Array函数允许你在代码执行中间创建一个数组,而不必事先确定其大小。该函数总是返回一个
Varant数组。使用函数Array你可以快速地将一系列数据放置在一个清单里面。下面的过程CarInfo
创建了一个叫做auto的固定大小,一维的三个成员的数组。
1。 在当前工程里插入一新模块,重命名为Array_Function
2。 输入下列过程CarInfo:
Option Base 1
Sub CarInfo()
Dim auto As Variant
auto = Array(〃Ford〃; 〃Black〃; 〃1999〃)
MsgBox auto(2) & 〃 〃 & auto(1) & 〃; 〃 & auto(3)
auto(2) = 〃4…door〃
MsgBox auto(2) & 〃 〃 & auto(1) & 〃; 〃 & auto(3)
End Sub
另外一个例子,示范如何使用Array函数将列标输入到工作表里:
Sub ColumnHeads()
Dim heading As Variant
Dim cell As Range
Dim i As Integer
i = 1
heading = Array(〃First Name〃; 〃Last Name〃; 〃Position〃; _
〃Salary〃)
Workbooks。Add
For Each cell in Range(〃A1:D1〃)
cell。Formula = heading(i)
i = i+1
Next
Columns(〃A:D〃)。Select
Selectionlumns。AutoFit
Range(〃A1〃)。Select
End Sub
10。IsArray 函数
使用IsArray函数你可以测试某个变量是否数组。如果该变量是个数组,那么IsArray函数返回True,
否则返回False。请看例子:
1。 在当前工程里插入模块,命名为IsArray_Function
2。 输入如下过程IsThisArray:
Sub IsThisArray()
'declare a dynamic array 声明一动态数组
Dim sheetNames() As String
Dim totalSheets As Integer
Dim counter As Integer
'count the sheets in the current workbook 计数当前工作簿里的工作表数目
totalSheets = ActiveWorkbook。Sheetsunt
'specify the size of the array 明确数组大小
ReDim sheetNames(1 To totalSheets)
'enter and show the names of sheets 输入和显示工作表名称
For counter = 1 to totalSheets
sheetNames(counter) = ActiveWorkbook。Sheets(counter)。Name
130
… 页面 147…
MsgBox sheetNames(counter)
Next counter
'check if this is indeed an array 检查它是否确实为数组
If IsArray(sheetNames) Then
MsgBox 〃The sheetNames is an array。〃
End If
End Sub
11。Erase 函数
当你要清除数组里的数据时,应该使用Erase函数。该函数删除静态或动态数组储存的所有数据,
另外,对于动态数组,Erase函数将重新分配原来分配给该数组的所有内存。下面的例子教你如何
删除数组cities里的数据。