第六章 过程
6.1 Sub过程
6.2 Function过程
6.3 参数传递
6.4 可选参数和可变参数
6.5 对象参数
6.6 作用域和生存期
6.7 常用算法举例
VB已提供的过程,内部函数过程、事件过程;
用户可自编过程,Sub子过程,Function函数过程。
6.1 Sub过程由用户编写的、能完成一系列操作动作并实现一定功能的 独立程序模块 称作自定义 Sub过程(子过程) 。
6.1.1 Sub过程的建立
1,引例例 6-1 编程实现如下功能:
单击窗体时打印如图 6-1所示的图案。
子图案 1,由 5行字母,A”组成 正立三角形 ;
子图案 2,由 5行字母,V”组成 倒立三角形 。
Draw1(),打印子图案 1 ;
Draw2(),打印子图案 2。
也可以将 Draw1()和 Draw2()整合成一个带参数的
Draw12(i),i=奇数:完成 Draw1()功能,
i=偶数:完成 Draw2( )功能 (见 例 6-1a)。
图 6-1使用 Sub过程
2,SUB过程的一般形式
[Static][Public|Private] Sub 子过程名 ( [参数列表 ] )
局部变量或常数的定义语句块 1
[Exit Sub]
语句块 2
End Sub
理解各部分的含义 。
6.1.2 Sub过程的调用调用 Sub过程的一般形式有二:
(1) Call 子过程名 ([参数列表 ])
(2)子过程名 [参数列表 ]
说明:
(1) 有 Call关键字,则提供的参数也 有 小括号;
(2) 无 Call关键字,则提供的参数也 无 小括号 。
(3) 如果没有参数,则都不加小括号。
过程首部过程体
6.2 Function过程例 6-2 求 s=1!+2!+3!+4!+5!+6!的值,并打印结果。
【 分析 】 可以编写一个函数过程专门计算阶乘;这个求阶乘的函数过程在此我们取名为 Fac。
定义函数过程
Private Function Fac(n%) As Long
Dim i%,Result#
Result = 1
For i = 1 To n
Result = Result * i
Next i
Fac = Result
End Function
调用函数过程,
Private Sub Form_Click()
Dim m%,Sum #
Sum = 0
For m= 1 To 5
Sum = Sum + Fac(m)
Next m
Print"1!+2!+… +5!="; Sum
End Sub
6.2.1 Function过程的定义函数过程的一般格式如下:
[Static][Public|Private] Function 函数名 ( [参数列表 ] ) [AS 类型 ]
局部变量或常数的定义语句块 1
[Exit Function ]
语句块 2
函数名=返回值
End Function
函数名 命名规则同变量名。
函数首部末尾的 [AS 类型 ] 是指 函数名的类型,也就是 返回值的类型函数名 = 返回值,必须在函数体内至少对函数名赋值一次。
[Exit Function],表示退出函数过程 。
函数首部函数体
6.2.2 Function过程的调用调用 Function过程的一般形式:
变量=函数名 ([参数列表 ])
说明:
( 1) 这里提供的 [参数列表 ]是一些值已知的参数;称 实参 。
( 2) 函数过程的调用也可以出现在输出列表中,或作为一个表达式的参数参与计算 。 如:
Print Fac(5)
Y= Sqr(2 * Fac (6) - 1)
( 3) 如果有时对函数的值不需要,也可以写成一个独立的调用语句,如:
Call 函数名 ([参数列表 ])
有 Call,函数名后面必须也有括号 。
函数名 [参数列表 ]
函数名 ([参数列表 ])
无 Call,函数名后面的括号可有可无 。
6.2.3 通用过程和事件过程
VB中的过程可以分为 通用过程 和 事件过程 两类 。
通用过程,就是可以被一切其他过程调用的过程,包括上面所介绍的 Sub过程和 Function过程;它们在被调用时才执行 。
事件过程,是 VB内部已经预定义好的一些过程,但过程的代码需要用户填写;它们是在发生一定事件的时候被执行 。
通用过程可以写在一个 窗体模块 的代码中,也可以写在 标准模块 或 类模块 的代码中。而事件过程只能写在 窗体模块 中。
例:改写 6-1,增加模块
6.3 参数传递
6.3.1 形参和实参形参,在过程定义模块首行过程名括号中设置的参数叫做形式参数,简称形参 。 局部变量,也叫做虚参 。 内存单元临时分配 。
被调过程执行完后,形参变量的内存单元被,释放,。
实参,主调过程中调用过程时所给出的具体参数,这些参数是有确定值的 ( 所以说是,实,的 ),它们可以是直接常量或有值的变量表达式 。
实参 5
Private Function Fac(n As Integer) As Long
……………
Fac = Result
End Function
形参 n
调用语句,Y=Fac(5) 实参 形参传值 /传地址参数列表形式,[ByVal] 变量名 [( )] [As 类型 ]
6.3.2引用 (传地址 )
过程定义中 无,ByVal”关键字; 形参得到的是实参的地址,
当形参的值发生改变时,实参的值也相应发生改变。 双向影响。
6.3.3 传值过程定义中 有,ByVal”关键字;形参得到的是实参的值,形参和实参各有不同存储单元,形参值的改变不会影响实参的值。
单向影响。
例 6-3 分析下列程序的运行结果
Private Sub multi (x!,ByVal y!)
Print "x="; x; ";y="; y
x = 2 * x
y = 2 * y ’多个参数则按其位置
End Sub ’顺序一一对应
Private Sub Form_Click()
Dim a As Single,b As
Single
a = 2.5
b = 3.5
Call multi(a,b)
Print "a="; a; ";b="; b
End Sub
输出结果是:
x=2.5; y=3.5
a=5; b=3.5
例 6-4 试分析下列程序运行后的输出结果 。
Private Sub Swap1(x As Single,y As Single)?引用
Dim t As Single
t = x,x = y,y = t
End Sub
Private Sub Swap2(ByVal x As Single,ByVal y As Single)?传值
Dim t As Single
t = x,x = y,y = t
End Sub
Private Sub Form_Click()? 主调过程
Dim a As Single,b As Single,c As Single,d As Single
a = 5,b = 6,c = 15,d = 16
Call Swap1(a,b),Call Swap2(c,d)
Print "a="; a; ";b="; b
Print "c="; c; ";d="; d
End Sub
输出结果:
a=6; b= 5
c=15; d= 16
6.3.4 指名传送在调用自定义通用过程时,把形式 ( 虚拟 ) 参数用,,=”与实际参数联系起来,这种参数传递方式叫 指名传送 。
Sub Sub1(x As Single,y As Single,z As Single)
Print x,y,z
End Sub
Private Sub Form_Click()
Dim a As Single,b As Single
a = 2,b = 3
Call Sub1(z:=9,y:=b,x:=a)
End Sub
运行时将在窗体上输出,2 3 9
通过以上调用语句 Call Sub1(z:=9,y:=b,x:=a)可知,采用指名传送方式时,给形参指名传送值的顺序可以随意,不一定要按形参的原始设置顺序。
6.3.5 数组参数的传递
1,形参是普通变量,实参可以是普通变量或数组元素这种情况跟前面所讲的内容没有区别,因为一个数组元素本来就是一个普通变量 。 所以在使用方法上与普通变量相同 。
例 6-5 本程序中函数过程 IsPrim(x)的功能是判断一个变量 x的值是否为素数,其函数返回值分别为 True(当 x是素数时)或 False
(当 x不是素数时)。在调用过程中分别对数组 a的每个元素值调用此函数,以判断每个元素是否为素数,并输出其中为素数的元素。
注意:
此程序中函数过程 IsPrim(x)中的形参 x是一个普通变量,所以调用语句 IsPrim(a(i))中的实参可以是一个数组元素 a(i)。
6.3.5 数组参数的传递
2,形参是带括号的数组名,实参也必须是带括号的数组名这时只能采用 传地址 方式 。 在使用这种参数时要注意:
形参 不指定数组的具体维数,仅留圆括号 (以示为数组 ) ;
实参 也仅仅是带园括号的数组名 (但该数组已经有具体值 )。
在被调过程的代码中可以用 Lbound和 Ubound函数形式上求解 数组下标的 下界,上界 。
例 6-6 编一函数 tim,求任意一维数组中各元素之积。分别求下列两式的值:
i
i
at
5
1
1

i
i
bt
6
2
2

例 6-6 程序如下:求数组各元素乘积的通用过程 tim( ):
Function tim(a( ) As Integer)
Dim t#,i%
t = 1
For i = Lbound(a) To Ubound(a)
t = t * a(i)
Next i
tim = t
End Function
调用通用过程 tim( ),分别求两个数组的元素之积:
Sub Command1_Click( )
Dim a%(1 To 5),b%(2 To 6),i%,t1#,t2#
… … ' 给数组 a()、数组 b()赋值语句略
t1 = tim(a( )) '求数组 a()各元素的乘积
t2 = tim(b( )) '求数组 b()各元素的乘积
Print t1,t2
End Sub
使用自定义过程的注意事项:
1,确定自定义的过程是子过程还是函数过程函数过程名有值,子过程名无值。
2.过程中形参的个数和传递方式的确定过程中参数的作用是实现过程与调用者的数据通信。
(1) 从主调程序获得初值,形参和实参占两个不同单元,是值传递。
(2) 从主调程序获得实参地址,形参和实参是同一单元,地址传递。
3,实参与形参结合时对应问题个数、类型、位置、次序一一对应。
形参是 值传递,对应实参可以是 表达式、常量、数组元素。
形参是 地址传递,对应实参只能是 有值变量名、有值数组名,
等。
6.4 可选参数和可变参数
6.4.1 可选参数可选形式参数前用关键字 Optional指定 。
例 6-7 分别计算 圆的面积 和 圆柱体积 。 本例题中 通用的 函数过程 F1既可 计算 圆的面积 又可计算 圆柱体积,其 中的 h是可选参数 。
Private Function F1(r As Single,Optional h)
F1 = 3.1415926 * r * r
If Not IsMissing(h) Then ' IsMissing(h)函数检测实际参数是否有 h
F1 = F1 * h
End If
End Function
6.4.1 可选参数
Private Sub Command1_Click()
Dim r As Single,h As Single
r = 10,h = 10
Print,第一次调用,计算圆的面积 ="; F1(r)
Print,第二次调用,计算圆柱体积 ="; F1(r,h)
End Sub
说明:
( 1) 可选参数必须是变体类型 。
( 2) 对含可选参数的过程,要用到函数 IsMissing(h)来检测可选参数对应的实际参数是否存在 。 如果实际参数不存在,则该函数的值为 True;如果实际参数存在,则该函数的值将为 False。
所以例 6-7中 If Not IsMissing(h) Then 语句也可以写成:
If IsMissing(h) =False Then。
6.4.2 可变参数
VB也可以在一些数组名形式参数前加关键字 ParamArray使该参数定义为可变参数,则允许其对应的实参个数为任意数目 。
例 6-8 可变参数的演示 。 要编写一个函数实现对任意个数的参数求和,可编写如下带可变参数的通用函数过程:
Public Function NumSum(ParamArray dst( )) As Long
Dim i As Long
NumSum = 0
For i = LBound(dst) To UBound(dst)
NumSum = NumSum + dst(i)
Next i
End Function
在主调函数中,若用 s = NumSum(1,2,3)语句调用 NumSum函数,
则求出 1+2+3的和;而用 s = NumSum(1,2,3,4)语句调用,则求出 1+2+3+4的和。
6.5 对象参数
VB也允许把对象作为参数进行传送,这样的参数称为对象参数 。
对象参数有两类,即 控件参数 和 窗体参数 。
6.5.1控件参数例 6-9 控件参数的演示 。 本题窗体上有一个文本框控件和一个标签控件及两个命令按钮 。 单击按钮 1则实现对文本框的移动;单击按钮 2则实现对标签的移动 。 自定义过程的其余两个参数 x和 y则分表表示对象在水平方向和垂直方向要移动的距离 。
Sub MoveControl( t As Control,x As Single,y As Single) '带控件参数的过程
t.Move t.Left + x,t.Top + y
End Sub
调用语句,Call MoveControl(Text1,100,200)?移动文本框
Call MoveControl(Label1,-200,150)?移动标签
6.5.2 窗体参数例 6-10 本例题程序有三个窗体,其中窗体 Form1为启动窗体,在该窗体中编写了一个通用过程 ShowForm(t1 As Form,c As String),
参数 t1就是一个窗体参数,而参数 c是一个普通的字符串类型参数 。
窗体 Form1 中 还 编 写 了 两 个 事 件 过 程 Command1_Click() 和
Command2_Click(),在两个事件过程中分别用 Form2和 Form3( 另外两个窗体的名字 ) 作参数,调用 ShowForm过程,实现对不同窗体的显示 。
Sub ShowForm(t1 As Form,c As String) '带窗体参数的自定义过程
t1.Show,t1.Print c
End Sub
调用语句,
Call ShowForm(Form2,“欢迎进入窗体 2”) '显示窗体 2
Call ShowForm(Form3,“欢迎进入窗体 3”) '显示窗体 3
6.6 作用域和生存期
6.6.1 常量、变量及数组的作用域和生存期
1.局部变量,作用域为过程范围内;生存期为过程调用期。
Dim关键字定义的局部变量是 动态局部变量,
Dim XXX As YYY
而 Static关键字定义的局部变量是 静态局部变量,
Static XXX As YYY
Static 过程名 ( [形参表 ] ) [AS 类型 ]
Static的作用是延长一个局部变量的生存期,但并不扩大其作用域。
例 6-11 动态局部变量和静态局部变量的演示。
图 6-3动态变量和静态变量的区别在 Command1_Click()过程中 5次调用函数
Sum1();而在 Command2_Click()过程中 5
次调用函数 Sum2()。 Sum1()中 的局部变量 j为动态; Sum2()中 的局部变量 j为静态 。
程序运行结果如图 6- 3所示。
6.6.1 常量、变量及数组的作用域和生存期
2,窗体级变量作用域,窗体级变量可以被窗体内的所有过程访问。
生存期,与窗体的生存期一样,只要窗体不消失,它就不消失。
定义方式,参见图 6-4中的变量 A和 B。
3,模块级变量作用域,模块级 变量可以被本模块内的所有过程访问。
生存期,与 模块 的生存期一样。
定义方式,参见图 6-5中的变量 W和 T。
图 6-4 窗体级变量的定义 图 6-5 模块级变量定义在通用声明处用 Dim或
Private定义
6.6.1 常量、变量及数组的作用域和生存期
4,全局变量作用域,整个工程的所有过程中均可使用 。
生存期,在应用程序运行过程中一直存在。
定义方式,在窗体或模块的,通用,/“声明,段用 Public进行定义。
对窗体中定义的全局变量,别的窗体引用时要加 限定词 ;而模块中定义的全局变量任何地方引用都不需要加 限定词 。
如 Form1中定义变量 X:
Public X As Single
在另一个窗体 Form2或模块中 引用该变量:
Form1.X=12 (给它赋值)
Z=Form1.X (使用它的值)
6.6.1常量、变量及数组的作用域和生存期局部变量,窗体 /模块级变量,全局变量的对比表
6.6.1常量、变量及数组的作用域和生存期
5,同名不同级的变量引用规则若在不同级声明相同的变量名,系统按 局部,窗体 /模块,
全局 的优先次序访问。如,
Public Temp As integer ' 全局变量
Sub Form_Load()
Dim Temp As Integer ' 局部变量
Temp=10 ' 访问局部变量
Form1.Temp=20 ' 访问全局变量必须加窗体名
Print Form1.Temp,Temp ' 显示 20 10
End Sub
6.6.2 过程和函数的作用域过程也分为 窗体级,模块级 和 全局级 三种类型。
1,窗体级窗体级的过程的作用范围只限于本窗体,即只能被本窗体中的其他过程所调用。定义形如:
Private Sub/Function XXX ( [形参表 ] ) [ AS 类型 ]
2,模块级模块级的过程的作用范围只限于本模块,即只能被本模块中的其他过程所调用。定义形如:
Private Sub/Function XXX ( [形参表 ] ) AS 类型 ]
3,全局级全局级的过程的作用范围为整个应用程序,即能被应用程序中所有其他过程所调用。定义形如:
[Public] Sub/Function XXX ( [形参表 ] ) [ AS 类型 ]
6.6.2 过程和函数的作用域窗体 /模块级,全局级过程的对比表
6.7.1 数制转换例 6-12 将一个十进制整数 m转换成 r (2- 16)进制字符串 。
方法:将 m不断除 r 取余数,直到商为零,以反序得到结果。
6.7 常用算法举例原理如图 6-6所示。设置三个关键变量:
被除数 m、除数 r、余数 mr。
mr=m Mod r
m = m \ r
(下一个被除数 m等于当前 被除数 m除以 r所得的整数商)。
图 6-7 数制转换程序界面思考:若要将 r( r≠ 10)进制数转换成十进制数,如何实现?
数制转换程序界面如图
6-7所示。
6.7.2 英文文本加密解密简单加密的思想:,移位变换,法。
将每个字母 c加一序数 k,得到变化后的 c,c=chr(Asc(c)+k)
例如序数 k为 5,这时,A”?“F”,,a”?“f”,,B”?“G”…
当加序数后的字母超过,Z”或,z”时,c=chr(Asc(c)+k -26)
解密为加密的逆过程。
图 6-8 加密解密程序界面例 6-13 编写一个加密解密程序,实现如下功能,对所输入的一行字符串中所有英文字母采用,移位变换,法加密,其他字符不变;并实现相应的解密算法 。
程序运行界面如图 6-
8所示 。
6.7.3 单词查找与替换例 6-14 给定一英文字符串,查找指定单词在字符串中出现的次数;并可以将该单词全部替换成另一指定的单词 。
【 分析 】 用 S变量存放给定的 字符串,S1变量存放 要查找的单词,S2变量存放要替换成的 新单词 ;变量 n计数 。 本程序分查找统计和替换两个功能模块 。
图 6-9 单词查找与替换程序界面程序运行界面如图
6-9所示 。
6.7.4 数组反序例 6-15 编写一个通用过程,该过程能将一个数组反序排列;
然后在窗体单击事件过程中用一个具体数组作为实参调用该通用过程,检验通用过程是否正确。
图 6-10 数组反序程序界面
【 分析 】 对一个数组 x()进行反序处理,关键算法就是交换元素的值 (设 n是元素总个数 ):
第 1个元素~第 n个元素交换 ;
第 2个元素~第 n-1个元素交换 ;
… … ;
第 i个元素~第 n-(i-1)个元素交换 ;
总共要交换的对数 n\2对。
程序界面如图 6-10所示 。