第 7 章 模块与 vba

Post on 05-Jan-2016

200 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

第 7 章 模块与 VBA. 概述. 本章要涉及到编程。了解编程基础知识,掌握程序的三种结构在 VBA 中的实现,能够读懂程序并写(填)出程序片段 模块基本概念 创建模块 VBA 设计基础 VBA 流程控制 过程调用和参数传递 程序错误处理和调试. 7.1 模块基本概念. 7.1.1 模块的概念 模块是 Access 数据库中一个重要的对象,用 VBA 语言编写,以函数过程( Function )和子过程为单元的集合方式存储。利用模块可以创建自定义函数、子过程和事件过程等,以便实现复杂的功能。 在 ACCESS 中,模块分为标准模块和类模块两种类型。. 创建模块. - PowerPoint PPT Presentation

TRANSCRIPT

第 7 章模块与 VBA

概述

本章要涉及到编程。了解编程基础知识,掌握程序的三种结构在 VBA 中的实现,能够读懂程序并写(填)出程序片段

1. 模块基本概念2. 创建模块3. VBA 设计基础4. VBA 流程控制5. 过程调用和参数传递6. 程序错误处理和调试

7.1 模块基本概念

7.1.1 模块的概念 模块是 Access 数据库中一个重要的对象,用 VBA

语言编写,以函数过程( Function )和子过程为单元的集合方式存储。利用模块可以创建自定义函数、子过程和事件过程等,以便实现复杂的功能。

在 ACCESS 中,模块分为标准模块和类模块两种类型。

创建模块

模块以过程为单元组成,一个模块包含一个声明区域和若干个过程 Sub 、函数 Function 。

过程创建一般格式[public|private][static] 过程名 ( 形参表 )语句Exit subEnd sub

调用过程Call 过程名 ( 参数表 )

Function 函数[public|private][static] 函数名 ( 形参表 )语句End Function

例题 7.1 编写一个求圆面积的函数 Area()对于该例题中出现的语句只要大体了解即可。

7.1 【添加过程】对话框

【例 7.1 】编写一个计算圆面积的函数过程 Area() 。Public Function Area(r as Single) as SingleIf r<=0 ThenMsgBox " 圆的半径必须大于零 ",vbCritical," 警告 "Area=0 ' 半径为零,设置函数返回值为 0Exit Function ' 结束函数过程运行End IfArea=3.14*r*rEnd Function函数过程的调用形式:函数过程名 ([< 实参 >])函数过程不能使用 CALL 来调用执行,需要直接引用函数名并加

括号来辨别,可以在查询、宏等中调用使用,函数过程的返回值可以直接赋给某个变量。

例如,假如在某个窗体中要计算半径为 8 的圆面积,并用变量 S保存圆面积值,可调用上面创建的 Area() 函数过程,调用命令格式为: s=Area(8) 。

7.2 VBA 编程基础

VBA 是一种计算机语言。 对象在 Access 中指表、查询、窗体、报表、页、

宏、模块、 DoCmd 等 认识 VBE 窗口

对 象 组 合框

事 件 组 合框

属 性 窗口

工 程 窗口 代 码 窗

立 即 窗口

标 准 工 具栏

代码编辑区

7.2.1 VBA 编程环境

VBA 语句书写原则一行一句,如果特别长可以用 _( 下划线 ) 隔开如果节省空间,可以用 : ( 冒号 ) 将多条语句写在同行VBE 可以自动识别语法错误,有颜色提示。

注释,给程序员看,对机器无用‘ ( 单引号后面就是注释内容 )rem 后面是注释内容

7.2.2 数据类型

Access 中提供了若干数据类型,如下:1. 整数 Integer2. 长整数 Long3. 单精度数 Single4. 双精度数 Double5. 货币 Currency6. 字符串 String7. 布尔型 Boolean8. 日期型 Date9. 变体类型 Variant10. 用户自定义类型

数据库对象

Datebase Connection Form Report Control QueryDef TableDef Command RecorderSet

常量、变量、数组

常量:不能改变的量。1. 直接常量2. 符号常量 Const 定义的常量3. 内部常量, Access 定义的常量4. 系统常量, True 、 False 、 Null 、 Yes 、 No 、

On 、 Off

变量

变量,可以改变的量。 变量命名

包含字母、数字、下划线、汉字,且不以数字、下划线开头,不区分大小写,不能与系统关键字冲突。

声明变量:在 VBA 中可以隐式声明显式声明, Dim

变量作用域局部变量、模块变量、全局变量

数据库对象变量的引用方法窗体名称 ! 控件名称 . 属性名称注意叹号和点号的使用

Function SafeSqr(num) Val_Temp=Abs(num) SafeSqr=Sqr(Val_Tem) End Function

例如: intX1%=1243 ' 定义 intX1 为一个整型变量 DouX2#=45665.456 ' 定义 douX2 为一个双

精度变量 StrX3$="Access" ' 定义 strX3 为一个字符串

变量

声明变量的一般方法是用 Dim...As[DataType] 结构,其中 As 指定变量数据类型。

Dim 语句使用格式为: Dim 变量名 As [ 数据类型 ] 如果不使用“数据类型”可选项,默认定义的变量为

Variant 数据类型。可以使用 Dim 语句在一行中声明多个变量。

例如: Dim strX As String ' 定义了 1 个字符型变量 strX Dim intX As Integer,strZ As String ' 定义了 1 个整

型变量 intX 和 1 个字符型变量 strZ Dim x ' 定义了 1 个变体 (Variant) 类型变

量 x Dim I,j,k As integer ' 只有 k是 integer 型, I与 j都是 Variant 型

表 7. 1 种变量的使用规则与作用域

作用范围 局部变量

模块变量 全局变量

声明方式 Dim 、Static

Dim 、 Private Public

声明位置 在子过程中

在窗体 / 模块的声明区域

在标准模块的声明区域

能否被本模块的其他过程存取

不能 能 能

能否被其他模块的过程存取

不能 不能 能

Access 建立的数据库对象及其属性,均可被看成是 VBA 程序代码中的变量及其指定的值来加以引用,与普通变量不同的是要使用规定的引用格式。

例如,窗体和报表对象的引用格式为:Forms( 或 Reports) 窗体 (或报表 ) 名称 ! 控件名称 [. 属性名称 ]关键字 Forms 或 Reports 分别指示窗体或报表对象类;感叹号 (!) 为分隔符,用于

分隔开父子对象;“属性名称”为可选项,若省略,则默认为控件的基本属性 Value 。注意:如果对象名称中含有空格或标点符号,引用时要用方括号把对象名称括起来。例如,要在代码中引用窗体 (Myform1) 中名为 Txtxh 的文本框控件,可使用以下语

句:Forms!Myform1!Txtxh="3020503323“若在本窗体的模块中引用,可以使用 Me 代替 Forms!Myform1 。语句变为:Me!Txtxh="3020503323"“Forms!Myform1!Txtxh” 在程序语句中的作用相当于变量,但它指示的是某个

Access 对象。当需要多次引用对象时,可以先声明一个 Control( 控件 ) 数据类型的对象变量,然后使用 Set关键字建立对象变量指向的控件对象。语句使用格式如下:

Dim Txtxhbl As Control ' 定义对象变量,数据类型为 Control( 控件 ) 数据类型

Set Txtxhbl=Forms!Myform1!Txtxh ' 为对象变量指定窗体控件对象以后要引用控件对象,可转为引用对象变量。例如:Txtxhbl="3020503323"等同于:Forms!Myform1!Txtxh="3020503323"

数组 数组是相同类型变量的集合 定义数组

Dim 数组名 ( 下界 to 上界 ) AS 类型默认下界为 0 零

数组引用通过数组明 ( 下标 ) 方法引用

二维数组Dim 数组名 (a to b,m to n) AS 类型列举一些关于数组定义、引用的例子单独考数组很少,一般与循环部分结合!

数组变量由变量名和数组下标组成,在 VBA 中不允许隐式说明数组,可用 Dim 语句来声明数组。数组声明方式为:

Dim 数组名 ([ 下标下界 to] 下标上界 ) As 数据类型 下标下界的缺省值为 0 ,数组元素为:数组名 (0)至数组名

( 下标上界 );如果设置下标下界非0 ,要使用 to选项。 在使用数组时,可以在模块的通用声明部分使用 Option

Base 来指定数组的默认下标下界是 0 或 l: Option Base 1 设置数组的默认下标下界为 l Option Base 0 语句的默认形式 数组有两种类型:固定大小的数组和动态数组。前者总保持

同样的大小,而后者在程序中可根据需要动态地改变数组的大小。

(1)固定大小的数组 例如: Dim IntArray(l0) As Integer 这条语句声明了一个有 11 个整型数组元素的数组,数组元素从 IntArray(0)

至 IntArray(l0) ,每个数组元素为一个整型变量,这里指定数组元素下标上界来定义数组。

VBA 中允许指定数组下标范围时使用 To ,如下例所示: Dim IntArray(-2 to 3) As Integer 该语句定义一个有 6 个整型数组元素的数组,数组元素下标从 -2 到 3 。 如果要定义多维数组,声明方式为: Dim 数组名 ( 数组第 1 维下标上界,数组第 2 维下标上界… ) As 数据类型 例如: Dim IntArray(3,5) As Integer 语句定义了一个二维数组,第一维有 4 个元素,第二维有 6 个元素。 类似的声明也可以用在二维以上的数组中。 例如: Dim MultArray(3,1 to 5,0 to 5) As Long 语句定义了一个三维数组,第一维有 4 个元素,第二维有 5 个元素,第三维

有 6 个元素,其中数组元素的总数为三个维数的乘积: 4×5×6=120 。

(2) 动态数组 在 VBA 中,还允许用户定义动态数组。很多情况下,不能明确知道数组中应

该有多少元素,可使用动态数组。动态数组中元素的个数是不定的,在程序运行中可以改变其大小。

动态数组的定义方法是:先使用 Dim 来声明数组,但不指定数组元素的个数,而在以后使用时再用 ReDim 来指定数组元素个数,称为数组重定义。在对数组重定义时,可以使用 ReDim 后加保留字 Preserve 来保留以前的值,否则使用 ReDim 后,数组元素的值会被重新初始化为默认值。

【例 7.2 】定义动态数组 IntArray ,设默认下界为 1 ,并用循环赋值。 Dim IntArray() As Integer ' 声明动态数组 ReDim IntArray(5) ' 数组重定义,分配 5 个元素 For I = 1 To 5 ' 使用循环给数组元素赋值 IntArray(I) = I Next I Rem 数组重定义,调整数组的大小,并抹去其中元素的值。 ReDim IntArray(10) ' 重新设置为 10 个元素, IntArray(1) 至

IntArray(5) 的值不保留 For I = 11 To 20 ' 使用循环给数组元素重新赋值 IntArray(I) = I Next I

Rem 数组重定义,调整数组的大小,使用保留字 Preserve 来保留以前的值。

ReDim Preserve IntArray(15) ' 重新设置为 15 个元素, IntArray(1) 至 IntArray(10) 的值保留

For I = 11 To 15 ' 使用循环给未赋值数组元素赋值 IntArray(I) = I Next I Redim 语句只能出现在过程中,可以改变数组的大小和上下界,但不

能改变数组的维数。 执行不带 Preserve关键字的 Redim 语句时,数组中存储的数据会全部丢失。 VBA 将重新设置其中元素的值。对于 Variant 变量类型的数组,设为 Empty;对于 Numeric 类型的数组,设为 0 ;对于String 类型的数组则设为空字符串;对象数组则设为 Nothing 。

使用 Preserve关键字,可以改变数组中最后一维的边界,但不能改变这一维中的数据。

例如: Redim IntArray(10,10,10) Redim Preserve IntArray(10,10,15) 也就是说,在使用 Preserve关键字时,只能通过改变数组的上界来

重新设置数组的大小,改变数组的下界将会导致一个错误。如果改变后的数组比原来小,那么多出来的数据将会丢失。

(3) 数组的使用 数组声明后,数组中的每个元素都可以当作单个的变量来使用,其使用方法同相同类型的普通变量。数组元素的引用格式为:数组名 ( 下标值 ) 。

其中:如果该数组为一维数组,则下标值为一个范围为 [数组下标下界,数组下标上界 ]的整数;如果该数组为多维数组,则下标值为多个 ( 不大于数组维数 ) 用逗号分开的整数序列,每个整数 (范围为 [数组该维下标下界,数组该维下标上界 ]) 表示对应的下标值。

例如,可以如下引用前面定义的数组,设默认下界为 1 。 IntArray(2) ' 引用一维数组 IntArray 的第 2 个元素。 IntArray(2,2) ' 引用二维数组 IntArray 的第 2 行第 2 个元素。 【例 7.3 】若要存储一年中每天的支出,可以声明一个具有 365 个元素的数

组变量,而不是 365 个变量,数组中的每一个元素都包含一个值。下列的语句声明数组 CurArray 具有 365 个元素,设默认下界为 1 。

Dim CurArray (1 to 365) As Currency ' 声明一个具有 365 个元素的一维数组

Dim intI As Integer For intI=1 to 365 CurArray(intI) = 10 '每个数组元素都赋予一个初始值 10 Next

运算符、表达式

运算符1. 算术运算符

+ - * / \ mod ^2. 字符串运算符 + & ,推荐使用 &3. 关系运算符

= > < <= >= like is between..and4. 逻辑运算符

and or not5. 对象运算符! .

【例 7.4 】算术运算符应用示例。 2^8 ' 计算 2 的 8 次方 2^(1/2) 或 2^0.5 ' 计算 2 的平方根 7/2 ' 标准除法,结果为 3.5 7\2 ' 整数除法,结果为 3 10 Mod 4 '取模运算,结果为 2 10 Mod 2 ' 结果为 0 10 Mod -4 ' 结果为 2 -10 Mod -4 ' 结果为 -2 -8.8 Mod 5 ' 结果为 -4 20 – True ' 结果为 21 ,逻辑量 True转化为数值 -1 20 + False +6 ' 结果为 26 ,逻辑量 False转化为数

值 0

【例 7.5 “】 &” 运算符应用示例。 Strx ="ABC" Strx&" 是大写英文字母 " ' 出错 Strx & " 是大写英文字母 " ' 结果为“ ABC 是大写英文字母”

"Access" & " 数据库教程 " ' 结果为“ Access 数据库教程”

"abcd" & 1234 ' 结果为“ abcd1234” "abcd" & "1234" ' 结果为“ abcd1234” "4321" & "1234" ' 结果为“ 43211234” 4321 & 1234 ' 结果为“ 43211234” "2+3" & "=" & (2+3) ' 结果为“ 2+3=5”

【例 7.6 “】 +” 运算符应用示例。 "4321"+1234 ' 结果为 5555 "4321"+"1234" ' 结果为“ 43211234” "abcd"+1234 ' 出错 4321+"1234" & 100 ' 结果为“ 5555100”

【例 7.7 】 Is关系运算符应用示例。 Dim s1,s2 As Control Set s1=Me!text1 Set s2=Me!text1 strx=s1 Is s2 'strx 值为“ True” 【例 9.10 】关系运算符应用示例。 Dim S ' 定义变量 S S=(5>2) ' 结果为 True S=(2>=5) ' 结果为 False S=("abcd">"abc") ' 结果为 True S=("王力 ">"刘力 ") ' 结果为 True S=(#2005/10/10#>#2004/10/12#) ' 结果为 True

【例 7.8 】逻辑运算符应用示例。 Dim S ' 定义变量 S S=(5>2 And 3>=4) ' 结果为 False S=(5>2 Or 3>=4) ' 结果为 True S=("abcd">"abc" And 3>=4) ' 结果为 False S=Not(3>=4) ' 结果为 True S=(5>2 Xor 3>=4) ' 结果为 True S=(5>2 Xor 4>=3) ' 结果为 False S=(2>5 Eqv 3>=4) ' 结果为 True S=(5>2 Eqv 3>=4) ' 结果为 False S=(5>2 Imp 3>=4) ' 结果为 False S=(5>2 Imp 4>=3) ' 结果为 True

表达式

表达式就是由常量、变量、运算符构成的字符串,表达式具有特定的唯一值。

表达式运算优先级

(1) 表达式的组成 表达式由字面值、常量、变量、运算符、函数、标识符、逻辑量和括

号等按一定的规则组成,表达式通过运算得出结果,运算结果的类型由操作数的数据和运算符共同决定。

注意:在 VBA 中,逻辑量在表达式中进行算术运算时, True 值被当成 -1 、 False 值被当成 0 处理。

(2) 表达式的书写规则 只能使用圆括号且必须成对出现,可以使用多个圆括号,但必须配对。 乘号不能省略。 X 乘以 Y 应写成 X*Y ,不能写成 XY 。 表达式从左至右书写,无大小写区分。 (3) 算术运算表达式的结果类型 在算术运算表达式中,参与运算的操作数可能具有不同的数据精

度, VBA规定运算结果的数据类型采用精度高的数据类型。 (4) 运算优先级 如果一个表达式中含有多种不同类型的运算符,运算进行的先后顺序由运算符的优先级决定。 VBA常用运算符的优先级划分如 7.2所示。

表 7.2 运算符的优先级

优先级

高 低

算术运算符 字符串运算符

关系运算符

逻辑运算符

指数运算 (^) &+

=<><><=>=

Not

负数 (-) And

乘法和除法 (* 、/)

Or

整数除法 (\)

取模运算(Mod)

加法和减法(+ 、 -)

关于运算符的优先级作如下说明:①不同类型运算符的优先级为:算术运算符 > 字符串运算符 >关系运算符 >逻辑运

算符②圆括号优先级最高。③所有关系运算符的优先级相同。也就是说,按从左到右顺序处理。④算术运算符和逻辑运算符必须按照表 7.2所列优先顺序处理。

算数函数函数 函数功能说明 示例 结果

Abs(N) 返回数值表达式 N 的绝对值 Abs(-2) 2

Int(N)返回不大于数值表达式 N 的最大整数

Int(-3.5)Int(3.5)

-43

Fix(N)去掉小数,返回数值表达式 N的整数部分

Fix(-3.5)Fix(3.5)

-33

Sqr(N) 返回数值表达式 N 的平方根 Sqr(9) 3

Rnd(N) 产生 0~1 之间的随机数 Rnd(1)产生一个 0~1之间的新的随机数

Round(N1[,N2])

对数值表达式 N1 进行四舍五入,保留数值表达式 N2 位小数,若N2 缺省,则进入四舍五入,保留到整数位。

Round(3.255,2)Round(4.55)

3.265

Sgn(N)

返回数值表达式 N 的符号 , 当N 大于 0 时,返回 1 ,等于 0时,返回 0 ,小于 0 时,返回 -1

Sgn(5)Sgn(0)Sgn(-20)

10-1

Sin(N) 返回数值表达式 N 的正弦值 Sin(0) 0Cos(N) 返回数值表达式 N 的余弦值 Cos(0) 1Tan(N) 返回数值表达式 N 的正切值 Tan(0) 0

字符函数函数 函数功能说明 示例 结果Left(S,N) 从字符串 S 左侧取 N 个字符 Left(" 数 据 库 技

术 ",2)" 数据 "

Right(S,N) 从字符串 S 右侧取 N 个字符 Right("ABCD ",2) "CD"Mid(S,N1,N2)

从字符串 S 的 N1 位置起,截取 N2 个字符。

Mid("ABCDEF ",2,3)

"BCD"

Len(S) 返回字符串所含字符数 Len("2013 全运会 ") 7

LTrim(S) 删除字符串的开始空格 LTrim("□□ABC□□")

"ABC□□"

RTrim(S) 删除字符串尾部空格 RTrim("□□ABC□□")

"□□ABC "

Trim(S)删除字符串的开始空格和尾部空格

Trim("□□ABC□□")

"ABC"

InStr(N,S1,S2)

从字符串 S1 的第 N 个字符开始检索字符串 S2 在 S1中出现的位置。 N 若缺省,则从左侧第一个字符开始检索。

InStr("ABCD","CD ") InStr(4 , "ABCDABCD ", "CD ")

3 7

UCase(S) 将字符串 S 中字母转成大写 UCase("abcd") "ABCD"LCase(S) 将字符串 S 中字母转成小写 LCase("ABCD") "abcd "Space(N) 生成 N 个空格组成的字符串 Space(5) 5 个空格

日期、时间函数函数 函数功能说明 示例 结果Date() 返回系统当前日期 Date()  Now() 返回系统的当前日期和时间 Now()  Time() 返回系统的当前时间 Time()  Year(D) 返回日期 D 的年份 Year(#2014-05-08#) 2014Month(D) 返回日期式 D 的月份 Month(#2014-05-08#) 5Day(D) 返回日期 D 的日 Day(#2014-05-08#) 8Hour(T) 返回时间表达式 T 的小时 Hour(#08:30:15#) 8Minute(T) 返回时间 T 的分钟 Minute(#08:30:15#) 30Second(T) 返回时间 T 的秒 Second(#08:30:15#) 15

DateAdd(C,N,D)

对日期 D 增加特定的时间间隔值 N 。

DateAdd("D",2, #2014-4-30#)DateAdd("M",2, #2014-4-30#)

2014-5-22014-6-30

DateDiff(C,D1,D2)

返 回 D2 与 D1 之 间 的 时间间隔

DateDiff("D", #2013-4-30#,#2014-4-30#)DateDiff("YYYY", #2013-4-30#,#2014-4-30#)

365  1

WeekDay(D)

计算日期 D 为星期几,结果为 1-7 之间的整数,其中 1 代表星期日, 2 代表星期一,……, 7 代表星期六)

WeekDay(#2014-5-1#) 5

类型转换

字符转成 ASCII 码 ASC( 字符串 ) ,只转换第一个 ASCII转成字符 Chr( 代码 ) 数字转字符 Str( 数值表达式 ) 字符转数字 Val( 字符串 )

流程控制语句 声明语句:命名或定义变量、常量、函数等 赋值语句:将表达式值赋给变量

变量名 = 表达式 Goto 语句 不推荐使用

7.3 VBA 程序控制结构7.31 顺序结构

声明语句

通过声明语句可以命名和定义过程、变量、数组或常量。当声明一个过程、变量或数组时,也同时定义了它们的作用范围,此范围取决于声明位置 ( 子过程、模块或全局 ) 和使用什么关键字 (Dim 、 Public 、 Static 或 Global 等 ) 来声明它。

例如,有如下程序段: Sub Myproc( ) Dim SinS as Single,SinR as Single Const P=3.14159 End Sub 上述语句声明定义了一个名为 Myproc 的子过程, Dim 语句

定义了 2 个名称分别为 SinS 和 SinR 的单精度数据变量, Const 语句定义了 1 个名为 P的符号常量。当这个子过程被调用或运行时,所有包含在 Sub 和 End Sub之间的语句都会被执行。

赋值语句 赋值语句用于指定一个值或表达式给变量或常量。使用格式为: [Let] 变量名 = 值或表达式 其中: Let 为可选项,在使用赋值语句时,一般省略。 例如: Dim SinS as Single,SinR as Single SinS=1234.567 Let SinR=12.3 关于使用赋值语句的说明: (1) 当数值表达式与变量精度不同时,系统强制转换成变量的精度。 例如: Dim IntN as Integer IntN=10.6 'IntN 为整型变量, 10.6 经四舍五入转换后赋值, IntN 值为 11 (2) 当表达式是数字字符串,变量为数值型,系统自动转换成数值类型再赋值,若表达式含有非数

字字符或空串时,赋值出错。 例如: IntN%="123" 'IntN 值为 123 IntN%="1a2 3" ' 出错,类型不匹配 (3) 不能在一个赋值语句中,同时给多个变量赋值。 例如:以下语句语法没有错误,但结果不正确。 x%=y%=z%=10 (4) 实现累加作用的赋值语句。 例如: n=n+1 ' 取变量 n 中的值加 1 后再赋给 n ,与循环语句结合,可实现计数 说明:还有一个赋值语句是 Set 语句,它用来指定一个对象给已声明为对象类型的变量, Set 关

键字不能省略。

标号和 GoTo 语句

GoTo 语句用于在程序执行过程中实现无条件转移。 格式为: GoTo 标号 程序执行过程中,遇到 GoTo 语句,会无条件地转到其后的“标号”位置,并从该位置继续执行程序。 标号定义时,名字必须从代码行的第一列开始书写,名字后加冒号“ :” 。 例如: …… Goto Label1 '跳转到标号为“ Label1” 的位置执行 …… Label1: ' 定义的“ Label1” 标号位置 …… 说明: GoTo 语句在早期的 Basic 语言中曾广泛应用。在 VBA 中,程序的执行流程可用结构化语句控制,除在错误处理的“ On

Error GoTo...” 结构中使用外,应避免使用 GoTo 语句。

顺序结构每条语句执行且执行一次。

选择(分支)结构根据条件真假,有些语句可能不执行,但执行部分只运行一次。

循环结构根据条件真假,有些语句可能执行多次,但也有可能一次也不执行!

7.3.2 分支结构

单分支、双分支、多分支 单分支

if 条件 then 语句块 双分支

if 条件 then 语句块 1else 语句块 2end if

多分支,即单双分支的嵌套注意: else总与最近的 if配对使用!!当嵌套层次太多时,可以考虑使用 case 语句

(1) 单分支结构 语句格式为: If < 条件表达式 > Then < 语句 > 或 If < 条件表达式 > Then < 语句块 > End If 功能:当条件表达式为真时,执行 Then 后面的语句块或语句,否则不做任何操作。

说明:语句块可以是一条或多条语句。在使用上边的单行简单格式时, Then后只能是一条语句,或者是多条语句用冒号分隔,但必须与 If 语句在一行上。

例如:比较两个数值变量 x 和 y 的值,用 x 保存大的值, y 保存小的值。语句如下:

If x<y Then t=x 't 为中间变量,用于实现 x 与 y 值的交换 x=y y=t End If 或 If x<y Then t=x: x=y: y=t

(2) 双分支结构 语句格式为: If < 条件表达式 > Then < 语句 1> Else < 语句 2> 或 If < 条件表达式 > Then < 语句块 1> Else < 语句块 2> End If 功能:当条件表达式为真时,执行 Then 后面的语句 1 或语句块 1 ,否则执行 Else 后

面的语句 2 或语句块 2 。 【例 9.12 】编写计算如下函数的程序语句。 If x>=0 Then y=Sqr(x) Else y=Abs(x) End If 或 If x>=0 Then y=Sqr(x) Else y=Abs(x) 本例亦可用单分支结构语句实现,读者可写出程序语句。 双分支结构语句只能根据条件表达式的真或假来处理两个分支中的一个。当有多种条件时,要使用多分支结构语句。

(3) 多分支结构 语句格式为: If < 条件表达式 1> Then < 语句块 1> ElseIf < 条件表达式 2> Then < 语句块 2> …… Else < 语句块 n+1> End If 功能:依次测试条件表达式 1 、条件表达式 2 、……,当遇到条件表达式为真时,则执行该条件下的语句块。如均不为真,若有 Else选项,则执行 Else 后的语句块,否则执行 End If 后面的语句。

说明:不管条件分支有几个,程序执行了一个分支后,其余分支不再执行。当有多个条件表达式同时为真时,只执行第一个与之匹配的语句块。因此,应注意多分支结构中条件表达式的次序及相交性。另外注意 ElseIf 中不能有空格。

【例 7.9 】用窗体实现如下操作:当输入某同学期末考试科目的总平均成绩时,显示该生对应的五级制总评结果。

在窗体中添加以下控件: 创建 2 个标签控件,其标题分别设为:总平均成绩和总评结果。 创建 2 个文本框控件,其名字分别设为: Zpcj 和 Zpjg 。 创建 1 个命令按钮,其标题为“评定”,在其 Click 事件过程中,加入如下

代码语句: Private Sub command1_Click( ) If Me!Zpcj>=90 Then Me!Zpjg=" 优秀 " ElseIf Me!Zpcj>=80 Then Me!Zpjg=" 良好 " ElseIf Me!Zpcj>=70 Then Me!Zpjg=" 中等 " ElseIf Me!Zpcj>=60 Then Me!Zpjg="及格 " Else Me!Zpjg=" 不及格 " End If End Sub 运行结果:当在总平均成绩文本框中输入任何数值数据时,单击【评定】按钮,

总评结果将显示在总评结果框中。

(4)If 语句的嵌套使用: 指 If 或 Else 后面的语句块中又包含有 If 语句。语句格式为: If < 条件表达式 1> Then < 语句块 1> If < 条件表达式 11> Then < 语句块 11> End If End If 【例 9.14 】比较 3 个数值变量 x 、 y 和 z的值,通过交换,使得 x>y>z 。 程序语句如下: If x<y Then t=x: x=y: y=t ' 如果 x<y , x 与 y 交换,使得 x>y If y<z Then t=y: y=z: z=t ' 如果 y<z , y 与 z 交换,使得 y>z If x<y Then t=x: x=y: y=t '此时的 x , y 值已不是原先的值 End If End If End If 注意:嵌套 If 语句应注意书写格式,为提高程序的可读性,多采用锯齿型。注意 If 与

End If 的配对。多个 If嵌套, End If 与它最近的 If配对。

多分支 Select Case 语句 Select Case 语句格式为: Select Case 变量或表达式 Case 表达式 1 < 语句块 1> Case 表达式 2 < 语句块 2> … [Case Else < 语句块 n+1>] End Select 功能: Select 语句首先计算 Select Case 后 < 变量或表达式 > 的值,然后依次计算每个 Case 子句中表达式的值,如果 < 变量或表达式 >的值满足某个 Case 值,则执行相应的语句块,如果当前 Case 值不满足,则进行下一个 Case 语句的判断。当所有 Case 语句都不满足时,执行 Case Else 子句。如果条件表达式满足多个 Case 语句,则只有第一个 Case 语句被执行。

说明: “变量或表达式”可以是数值型或字符串表达式。 Case

表达式与“变量或表达式”的类型必须相同。 Case 表达式可以是下列几种格式: ①单一数值或一行并列的数值,之间用逗号分开。 ②用关键字 To 分隔开的两个数值或表达式之间的范围,前一个值必须比后一个值要小。字符串的比较是从它们的第一个字符的 ASCII 码值开始比较的,直到分出大小为止。

③用 Is关系运算符表达式。 例如: Case 1 to 20 Case is>20 Case 1 To 5,7,8,10,is>20 Case "A" To "Z"

【例 7.10 】判定学生总评成绩的代码可改写如下: Select Case Val(me!Zpcj) Case is>=90 me!Zpjg="优秀 " Case 80,81,82 to 89 me!Zpjg="良好 " Case 70 to 79 me!Zpjg=" 中等 " Case 60 to 69 me!Zpjg=" 及格 " Case Else me!Zpjg=" 不及格 " End Select 又例如: Dim strx as string *1 Select Case strx Case "A" to "Z", "a" to "z" stry="英文字母 " Case "!","?",",",".",";" stry=" 标点符号 " Case Is<68 stry=" 字符的 ASCII 码值小于 68" Case Else stry="其他字符 " End Select

7.3.3 循环语句 (1)Do While…Loop 循环语句 语法格式为: Do While 条件表达式 < 语句块> [Exit Do] < 语句块> Loop 功能: Do While 循环语句:当条件表达式结果为真时,执行循环体,直到条件表达式结果为假或执行到 Exit

Do 语句而退出循环体。 (2)Do Until…Loop 循环语句 语法格式为: Do Until 条件表达式 < 语句块> [Exit Do] < 语句块> Loop Do Until 循环语句:当条件表达式结果为假时,执行循环体,直到条件表达式结果为真或执行到 Exit

Do 语句而退出循环体。

(3)Do…Loop While 循环语句 语法格式为: Do < 语句块> [Exit Do] < 语句块> Loop While 条件表达式 说明: 关键字 While 用于指明当条件为真 (True) 时,执行循环体中的语句。 (4)Do…Loop Until 循环语句 语法格式为: Do < 语句块> [Exit Do] < 语句块> Loop Until 条件表达式 说明: 关键字 Until 用于指明当条件为真 (True) 前执行循环体中的语句。 对于 (1) 和 (2) 循环语句先判断后执行,循环体有可能一次也不执行;而对于 (3) 和 (4) 循环语句为先执行后判断,循环体至少执行一次。

在 Do…Loop 循环体中,可以在任何位置放置任意个数的 Exit Do 语句,随时跳出 Do…Loop 循环。

如果 Exit Do 使用在嵌套的 Do…Loop 语句中,则 Exit Do 会将控制权转移到 Exit Do 所在位置的外层循环。

当省略 While 或 Until条件子句时,循环体结构变成如下格式: Do < 语句块> [Exit Do] < 语句块> Loop 循环结构仅由Do... Loop 关键字组成,表示无条件循环,若在循环体中不加 Exit Do 语句,循环结

构为“死循环”。

【例 7.11 】把 26 个小写英文字母赋给数组 strx 。 Dim strx(1 to 26) As String I=1 Do While I<=26 strx(I)=Chr(I+96) I=I+1 Loop

For…Next循环语句

主要用于循环次数已知的循环操作。语句格式为: For 循环变量 = 初值 To 终值 [step 步长值 ] < 语句块> [Exit For] < 语句块> Next 循环变量 功能: 循环变量先被赋初值。 判断循环变量是否在终值内,如果是,执行循环体,然后循环变量加步长值继续;

如果否,结束循环,执行 Next 后的语句。 说明:循环变量必须为数值型。 step步长值:可选参数。如果没有指定,则 step 的步长值默认为 1 。注意:步长值可以是任意的正数或负数。一般为正数,初值应小于等于终值;若为负数,初值应大于等于终值;步长值不能为 0 ,否则造成“死循环”。

【例 7.12 】把 26 个大写英文字母赋给数组 strx 。 Dim strx(1 to 26) As String I=1 For I=1 To 26 strx(I)=Chr(I+64) Next I 说明:循环体结束后,循环变量的值为循环终值 + 步长值,上例循环结束后 I值为 27 。 【例 9.18 】分析下列程序的循环结构: For K=5 To 10 Step 2 K=K*2 Next K 按照公式计算,循环次数为: (10-5+1)/2=3次,但这是错误的。实际上,该循环的

循环次数为只有 1 次 ( 循环变量先后取值 5 和 12 ,循环执行 1 次之后,循环变量值为12 ,超过终值 10 ,循环结束 ) 。

【例 9.19 】在立即窗口中显示有 (*) 组成的 5*5 的正方形。 Sub Procedure5( ) ' 输出 5*5 的正方形 Const MAX=5 ' 定义常量 Dim Str As String Str="" For n=1 to Max Str=Str+"*" Next n For n=1 to Max Debug.print Str Next n End Sub

While…Wend循环语句

While…Wend循环与 Do While…Loop 结构类似,但不能在 While…Wend循环中使用 Exit Do 语句。

While…Wend循环语句格式为: While 条件表达式 < 语句块 > Wend

7.4 过程调用和参数传递

函数调用函数名称 ( 参数表 )

过程调用Call 过程名称 ( 参数表 )

参数传递ByVal 传值方式,单向ByRef 传址方式,双向举例子说明!

【例 7.13 】在窗体对象中,使用函数过程实现任意半径的圆面积计算,当输入圆半径值时,计算并显示圆面积。

在窗体中添加以下控件: 创建两个标签控件,其标题分别设为:半径和圆面积。 创建两个文本框控件,其名字分别设为: SinR 和 SinS 创建一个命令按钮,其标题设为“计算”,在其 Click 事件过程中,加入如下

代码语句: Private Sub command1_Click( ) me!SinS=Area(me!SinR) End Sub 在窗体模块中,建立求解圆面积的函数过程 Area() 。代码如下: Public Function Area(R As Single) As Single IF R<=0 Then Msgbox "圆半径必须为正数值 !",vbCritical, "警告 " Area=0 Exit Function End If Area=3.14*R*R End Function 运行结果:当在半径文本框中输入数值数据时,单击【计算】按钮,将在圆面积文本框中显示计算的圆面积值。

子过程的调用有两种方法,语句格式为: Call 子过程名 [( 实参列表 )] 和 子过程名 [实参列表 ] 说明: 用 Call关键字调用子过程时,若有实参,则必须把

实参用圆括号括起,无实参时可省略圆括号;不使用 Call关键字,若有实参,也不用圆括号括起。

【例 7.14 】在窗体对象中,使用子过程实现数据的排序操作,当输入两个数值时,从大到小排列并显示结果。

在窗体中添加以下控件: 创建两个标签控件,其标题分别设为: x 值和 y 值。 创建两个文本框控件,其名字分别设为: Sinx 和 Siny 创建一个命令按钮,其标题设为“排序”,在其 Click 事件过程中,加入如下代码语句: Private Sub command1_Click( ) Dim a,b If Val(me!Sinx)>Val(me!Siny) Then Msgbox "x 值大于 y 值,不需要排序 ",vbinformation, "提示 " Me!Sinx.SetFocus Else a= Me!Sinx b= Me!Siny Swap a,b Me!Sinx = a Me!Siny = b Me!Sinx.SetFocus End If End Sub 在窗体模块中,建立完成排序功能的子过程 Swap 。代码如下: Public Sub Swap(x,y) Dim t t=x x=y y=t End Sub 运行窗体,可实现输入数据的排序。 在上面的例子中, Swap(x,y)子过程定义了两个形参 x 和 y ,主要任务是:从主调程序获得初值,又将

结果返回给主调程序,而子过程名 Swap 是无值的。

参数传递

在 VBA 中,实参向形参的数据传递有两种方式,即传值 (ByVal选项 ) 和传址 (ByRef选项 ) ,传址调用是系统默认方式。区分两种方式的标志是:要使用传值的形参,在定义时前面加有“ ByVal”关键字,有“ ByVal”关键字,为传值方式,否则为传址方式。

(1) 传值调用的处理方式是:当调用一个过程时,系统将相应位置实参的值复制给对应的形参,在被调过程处理中,实参和形参没有关系。被调过程的操作处理是在形参的存储单元中进行,形参由于操作处理引起的任何变化均不反馈、影响实参的值。当过程调用结束时,形参所占用的内存单元被释放,因此,传值调用方式具有单向性。

(2) 传址调用的处理方式是:当调用一个过程时,系统将相应位置实参的地址传递给对应的形参。因此,在被调过程处理中,对形参的任何操作处理都变成了对相应实参的操作,实参的值将会随被调过程对形参的改变而改变,传址调用方式具有双向性。

【例 7.15 】创建有参子过程 Test() ,通过主调过程 Main_click( )被调用,观察实参值的变化。

被调子过程 Test( ) : Public Sub Test(ByRef x As Integer) '形参x 说明为传址形式的整型

量 x=x+10 '改变形参x 的值 End Sub 主调过程 Main_click( ) : Private Sub Main_click( ) Dim n As Integer ' 定义整型变量 n n=6 ' 变量 n 赋初值 6 Call Test(n) MsgBox n ' 显示 n 值 End Sub 当主调过程 Main_click( )调用子过程 Test( ) 后,“ MsgBox n” 语句显示

n 的值已经发生了变化,其值变为 16 ,说明通过传址调用改变了实参 n 的值。 如果将主调过程 Main_click( ) 中的调用语句“ Call Test(n)” 换成“ Call

Test(n+1)” ,再运行主调过程 Main_click( ) ,结果会显示 n 的值依旧是 6 。表明常量或表达式在参数的传址调用过程中,双向作用无效,不能改变实参的值。

在上例中,需要操作实参的值,使用的是系统默认的传址调用方式,若使用传值调用方式,请读者分析处理结果的变化。

7.5 程序调试

该节内容可以融入到其他章节中,编写例子的时候进行调试、运行。

注意语法错误和逻辑错误的调试 调试的方法等

程序调试的概念 编写的程序难免存在错误,必须反复地检查改正,

直到达到预定的设计要求,方能投入使用。程序调试的任务就是发现并纠正程序中的错误,以保证程序能够可靠运行。调试通常分为三步进行:检查程序是否存在错误,确定出错位置,纠正错误。

调试需要经验,关键在查错,有时查出错误,但难以确定出错位置,这就无法纠正错误,纠正错误需要程序设计技术与技巧。

图 7.3 设置断点

图 7.4 【调试】工具栏

运行中断

重新设置

切换断点

逐语句

逐过程 跳出 立即窗口

本地窗口监视窗口

快速监视

top related