900 likes | 1.05k Views
第 8 章 过程. 教学要求. 掌握 VB 的两种过程:事件过程和通用过程 掌握 Sub 过程的定义 掌握 Function 过程的定义 掌握过程的调用 掌握参数的传递 —— 按值传递和按地址传递 掌握递归算法 掌握变量的作用域. 教学内容. 8.1 Sub 过程 8.2 Function 过程 8.3 过程调用 8.4 参数传递 8.5 递归过程 8.6 变量的作用域 8.7 程序示例. 模块化程序设计. 基本思想:将一个大的程序按功能分割成一些小模块 特点: 各模块相对独立、功能单一、结构清晰、接口简单
E N D
教学要求 • 掌握VB的两种过程:事件过程和通用过程 • 掌握Sub过程的定义 • 掌握Function过程的定义 • 掌握过程的调用 • 掌握参数的传递——按值传递和按地址传递 • 掌握递归算法 • 掌握变量的作用域 2
教学内容 8.1Sub过程 8.2Function过程 8.3 过程调用 8.4 参数传递 8.5 递归过程 8.6 变量的作用域 8.7程序示例 3
模块化程序设计 • 基本思想:将一个大的程序按功能分割成一些小模块 • 特点: • 各模块相对独立、功能单一、结构清晰、接口简单 • 控制了程序设计的复杂性 • 提高元件的可靠性 • 缩短开发周期 • 避免程序开发的重复劳动 • 易于维护和功能扩充 • 开发方法: 自上向下,逐步分解,分而治之 4
过程 事件过程 通用过程 子程序过程 Sub 函数过程 Function VB中过程的分类 5
8.1 Sub过程8.1.1 事件过程 • 当对象识别某事件后,进行的操作处理——以代码的形式存储在事件过程中。 • 分类: • 窗体事件过程 • 控件事件过程 6
1 定义事件过程 • [形式]: Private Sub Form_事件名([参数列表]) [局部变量和常数声明] 语句块 End Sub 完全由系统决定,用户无权修改 窗体的事件过程名中不使用其具体名称,而固定用Form 窗体事件固定有“Private”关键字,说明它是模块级的 7
2 窗体的Initialize、Load、 Activate、 Gotfocus事件 • Initialize(初始化)事件——配置窗体时触发 • Load(加载)事件——窗体装入内存时触发 • Activate(激活)事件——窗体被激活时触发 • Gotfocus事件(得到焦点)事件——窗体成为当前焦点时触发 • 窗体上无可视控件时,触发窗体的Gotfocus事件; • 窗体上有可视控件时,触发控件的Gotfocus事件; • 执行次序: Initialize Load Activate Gotfocus 8
注 意 • 窗体的Initialize、Load事件发生在窗体被显示之前,其中可放置系统初始化命令,但其中语句有所限制; • 窗体加载后,只要不被卸载,就不会再执行Initialize、Load事件,但Activate事件会多次发生; • 当访问另一窗体上的“非可视”数据或调用其中定义的全局过程时,只会触发该窗体的Initialize事件,而Load事件不触发; • 当访问另一窗体上的“可视”数据时,会同时触发该窗体的Initialize和Load事件; 9
3 定义控件的事件过程 • [一般形式]: Private Sub 控件名_事件名([参数列表]) [局部变量和常数声明] 语句块 End Sub 由系统决定,用户无权修改 控件的事件过程名中必须使用其具体名称 控件事件固定有“Private”关键字,说明它是模块级的 10
4 建立事件过程 • 打开“代码编辑器”窗口; • 先选定某对象,再选定事件过程; • 编辑代码; 过程 对象 11
n! c m = n m!(n-m)! 能不能简化? 共同代码 计算k! Private Sub Command1_Click() n = Val(Text1.Text) m = Val(Text2.Text) k = n t = 1 For i = 1 To k t = t * i Next i s = t k = m t = 1 For i = 1 To k t = t * i Next i s = s / t k = n - m t = 1 For i = 1 To k t = t * i Next i s = s / t Text3.Text = Str(s) End Sub 计算:
函数调用(三次) 函数定义 计算k! Private Sub Command1_Click() Dim m As Integer, n As Integer Dim i As Integer, k As Integer Dim t As Long, s As Long n = Val(Text1.Text) m = Val(Text2.Text) s = fact(n) / (fact(m) * fact(n - m)) Text3.Text = Str(s) End Sub Private Function fact(k As Integer) As Long Dim i As Integer fact = 1 For i = 1 To k fact = fact * i Next i End Function 使用函数 13
过程的引入: 在以下两种情况下,经常使用自定义过程: (1)应用程序中出现较频繁的处理,仅仅是每次处理的数据不同而已; (2)程序中比较复杂的算法,独立出来,增强程序的可读性; “过程”的引入使得整个程序的结构更加清晰,模块化更强。 14
8.1.2 通用过程 • 完成某一特定功能的程序段 ——通用过程(自定义) • 必须显式调用方可执行; • 分为: • 公有过程(Public) • 私有过程(Private) 15
1 通用Sub过程的定义 • [一般形式]: [Private|Public] [static] Sub <过程名>([<参数列表>]) <过程体> End Sub • [说明]: • (1) 以Sub开头,End Sub结束,,中间是过程体——包括变量声明和语句块; • (2) 以Private为前缀的过程是模块级的,以Public为前缀的过程是应用程序级的,缺省默认是Public; (3) Static 选项说明过程中的局部变量是静态变量; (4) 过程名的命名规则和变量名相同,在同一个模块中,过程名必须是唯一的; 16
说 明 (5) 参数列表中的参数称为形式参数,可以没有,但无参数时圆括号不能省略;有多个参数时,参数之间用逗号间隔; • (6)参数说明格式: • [Optional][ByVal|ByRef] <变量名>[()][As <数据类型>] • 其中: • a) 若参数是数组,则在变量名后面加一对圆括号,但无维界定义 • b) ByVal:指明参数传递方式是传值; • c) ByRef:指明参数传递方式是传地址,为缺省值; • d) 若参数是字符型的,必须是不定长字符串; • e)Optional:参数是可选的,必须定义在必选参数后面。 • (7) 当过程调用结束,即执行到End Sub语句,系统自动返回调用程序的调用语句处,执行调用语句的下一条语句; • (8) 过程不能嵌套定义,但可嵌套调用; • (9)Exit Sub语句的功能是提前退出过程调用,返回调用语句。 17
例: Private Sub Exchange(x As Integer,y As Integer) Dim Temp As Integer Temp=x : x=y : y=Temp End Sub 该通用过程实现交换功能,包含两个参数,均是ByRef形式的参数。 18
2 建立通用Sub过程 • 方法一:在“代码编辑窗口”的“通用”中自行输入; • 方法二:进入代码编辑器窗口,执行“工具”菜单的“添加过程”,在“添加过程”对话框中输入定义过程的名称、类型和范围后单击“确定”按钮,系统会自动在代码窗口添加自定义过程的框架。 19
② ① ③ ⑤ ④ 3 Sub过程调用 必须在事件过程或其它通用过程中显示调用。 Private Sub sub2(形参表) …… 过程语句 …… End Sub Private Sub sub1() …… Call Sub2(实参表) …… End Sub 主调程序 被调过程 注意 :一个过程或函数可以被调用多次; 20
Sub过程调用 [格式一]: Call <过程名>[(<实在参数表>)] [格式二]: <过程名> [<实在参数表>] [功能]:对已定义的过程进行调用。 如: P164 • Call Fact(x) • Fact x 21
说 明 (1)调用的过程必须是已经定义的,否则系统会出现“子程序或函数未定义”的信息提示; (2)实在参数可以是常量、变量或表达式; (3)实在参数的数目及类型要和定义时必选参数保持一致,否则系统会出现“参数不可选”的信息提示,参数之间用逗号间隔; (4)若子程序没有参数,则格式一中的括号可以省略; (5)格式一和格式二的区别在于:格式二的参数表无须括号,而是和过程名之间用空格隔开; 22
例8-2 试编写一个找出任意一个正整数的因子的程序 P165 23
程序说明: 定义子程序factor求因子,该子程序定义了两个参数,来传递求因子实现前的原始数据和返回功能实现后的结果数据; • Option Explicit • Private Sub Command1_Click() • Dim inta As Integer, st As String • inta = Text1 • Call factor(inta, st) • Text2 = st • End Sub 调用过程factor • Private Sub factor(ByVal n As Integer, s As String) • Dim i As Integer • For i = 1 To n - 1 • If n Mod i = 0 Then s = s & Str(i) • Next i • End Sub 定义过程 优点:程序即Sub过程的使用不仅可以缩短程序的长度,还能够使程序的结构更加清楚。 24
例:定义一个通用过程用以求一维数组中的最小值例:定义一个通用过程用以求一维数组中的最小值 Private Sub value(a() As Integer, min As Integer) Dim i As Integer min = a(1) For i = 2 To UBound(a) If a(i) < min Then min = a(i) Next i End Sub 25
8 . 2 Function 过程 Function过程的特点是返回一个值,因此我们通常也称之为自定义函数。通常我们利用Function过程得到一个数值或一个字符串或一个逻辑值。 [格式]: [Private|Public] Function <函数名>([参数列表]) [As <数据类型>] <函数体> End Function 函数返回值的类型 函数名=表达式 26
说 明 (1) 以Function开头,以End Function结束,中间是函数体; (2)函数名命名规则、参数列表的表示都和Sub过程相同; (3)As 数据类型:函数过程将由函数名返回一个值,值的类型由[As 数据类型]定义; ★ (4) 函数体中一定要有对函数名赋值的语句——函数名=表达式,否则返回相应类型的初值; ★ (5)函数体内可有Exit Function语句——无条件退出函数过程,返回主程序。 (6)Function过程不能嵌套定义,但可嵌套调用。 27
例:定义函数: 函数返回值的类型 Private Function f(ByVal x As Integer) As Integer f = 3*x^3-2*x^2+6*x-1 End Function 函数名=表达式 28
函数类型 传值的参数 例8-1:编写一个求n!的函数。 Private Function Fact(Byval n As Integer) As Long Dim K As Integer Fact=1 If n=0 Or n=1 Then Exit Function Else For K=1 To N Fact=Fact*K Next K End If End Function 函数名=表达式 29
2 调用 Function 过程 • [格式]:<函数名>([实在参数表]) • [功能]:返回一个函数值。 • [说明]: • (1)一般情况下,函数的调用出现在赋值语句中,并且在赋值号的右侧; • (2)若函数没有参数,函数名后的括号不能省略; • (3)虽然VB允许象调用Sub过程那样调用Function过程,但这样调用时系统不返回函数值,建议大家不要使用这种调用方法。 Call fact(x) Fact x这两种方法均放弃函数的返回值 例如: 30
函数类型 例:用函数实现求一维数组中的最小值,对比前例(Sub) Private Function min( a( ) As Integer ) As Integer Dim i As Integer min = a(1) For i = 2 To UBound(a) If a(i) < min Then min = a(i) Next i End Sub 函数名=表达式 31
例:定义函数用以判断一个数是否是素数 • Private Function Prime(N As Integer) As Boolean • Dim i As Integer • Prime = False • For i = 2 To N-1 • If N Mod i = 0 Then Exit For • Next i • If i =N then Prime = True • End Function 可省略,因Prime的初始值就是false 函数名=表达式 32
[例]:S=1!+2!+…+10! 对比p171 Private Sub Form_Click() Dim S As Long, i As Integer For i = 1 To 10 Next i Print ”S="; S End Sub 函数调用: S = S + Fact(i) Private Function Fact(n As Integer) As Long Dim i As Integer Fact = 1 For i = 1 To n Fact = Fact * i Next i End Function 函数名=表达式 33
例8-3:利用函数过程编写一个求两个正整数的最大公约数的程序例8-3:利用函数过程编写一个求两个正整数的最大公约数的程序 P166 Private Function Gcd(ByVal A As Integer, ByVal B As Integer) As Integer Dim R As Integer R = A Mod B Do While R <> 0 A = B B = R R = A Mod B Loop Gcd = B End Function Private Sub Form_Click( ) ‘ 主调过程 Dim N As Integer, M As Integer, G As Integer N = InputBox("输入N") M = InputBox("输入M") G = Gcd(N, M) Print N; "和"; M; "的最大公约数是:"; G End Sub 使用赋值语句调用函数 34
8.3.4 调用其他模块中的过程 • 1、调用其他窗体模块中的公有过程 • [格式]:Call <窗体名>.<过程名>[(<实在参数表>)] • [功能]:调用其他窗体模块中定义的公有过程。 Private Sub Form_Click() Dim a As Integer a = 10 Print Form1.Fact(a) End Sub 在Form2中调用 35
2、调用标准模块中的公有过程 • [格式]:Call [<标准模块名>.]<过程名>[(<实参表>)] • [功能]:调用其他标准模块中定义的公有过程。 • [说明]: • 若公有过程唯一,则直接调用,不加模块名。 • 若存在同名的公有过程,则: • 调用本模块中过程:直接调用,不加模块名 • 调用其它模块中过程:必须加模块名。 • 被调用的函数和过程必须是公有的; • 函数也可以这样调用。 36
调用类模块中的过程 • [格式]: • dim democlass as new class1 • call democlass.clssub ( [实参表] )] • [注意]: • 调用类模块中的共有过程,须用该类的某一实例修饰过程。 不做要求 37
8.4 参数的传递 8.4.1 形式参数和实在参数 • 形式参数: • 过程定义时,在过程名后面的圆括号里的一系列变量; • 过程被调用执行时,系统才给形参分配存储空间; • 可以是除定长字符串外的任一简单变量; • 可以是数组,变量名后接括号; • 简称“形参” St As String *3 × St( ) As String *3 √ St As String √ 38
实在参数 • 主调程序中,调用语句中,出现在过程名后面圆括号里的变量,是实在参数,可以是常量、变量或表达式; • 过程调用传递参数时,实参按“位置”和形参结合; • 实在参数和形式参数,要求个数一样,位置对应,类型一致,否则会出错; • 定长字符串变量可以作为实在参数; • 简称“实参” 39
参数结合: 40
举例: Private sub test(a as single,loc as booleaan,array1() as integer,chr1 as string) … End sub Private Sub Form_Click() Dim x as single , st as sting*5 Dim a(5) as integer Call test (x^2 ,true, a, st ) End sub 定长字符串 表达式 数组 常量 41
举例:写出下列程序执行的结果 Private Sub ExamSub( x as integer,y as integer) x=x+10 : y=y-10 End Sub 过程的先后顺序无所谓 Private Sub Form-click() Dim x as integer, y as integer x=10:y=100 Call ExamSub( y ,x ) Print “x=” ; x ; “y=” ; y End Sub 调用子过程时,进行的实际操作是y=y+10,x=x-10 42
8.4.2 按值传递参数 [格式]:ByVal <变量说明> [传递方式 ]: 调用时,系统为形参分配一个临时存储单元,并将实参的值存储到该临时单元中。 若在被调用的过程体中改变了形参的值,只是改变了临时存储单元中的数据,对实参的值无任何影响。 43
[参数传值传递]举例: Private Sub Form_Click() Dim M As Integer, N As Integer M = 15: N = 20 Call Value_change(M, N) Print "M="; M, "N="; N End Sub Private Sub Value_change(ByVal x As Integer, ByVal y As Integer) x = x + 20 y = y + 20 Print "X="; x, "Y="; y End Sub 44
传值是单向的: 实在参数 形式参数 调用时,实参将值传递给形参,两者就无任何关联。过程中形参的值发生变化,对实参无任何影响。 45
8.4.3 按地址传递参数 [格式]: ByRef <变量说明> [传递方式]: 系统在调用执行过程时,为形参分配临时存储单元,并将实参的内存单元地址传送给形参,存储在临时存储单元中 在被调用的过程体中一切对形参的操作,都是直接对地址保存在形参中的内存单元中的数据进行的,而实参就是保存在此内存单元中的数据,所以任何对形参的操作也就是对实参的操作; 按地址传递时,形式参数和实在参数共用同一“内存单元”。 46
[参数传址传递]举例:(对比前例) Private Sub Form_Click() Dim M As Integer, N As Integer M = 15: N = 20 Call Value(M, N) Print "M="; M, "N="; N End Sub Private Sub Value(x As Integer, y As Integer) x = x + 20 y = y + 20 Print "X="; x, "Y="; y End Sub 47
传地址是双向的: 实在参数 形式参数 48
举例:计算5!+4!+3!+2!+1! P171 Private Sub Form_Click() Dim Sum As Integer, I As Integer For I = 5 To 1 Step -1 Sum = Sum + Fact(I) Next I Print "Sum="; Sum End Sub Private Function Fact(n As Integer) As Integer Fact = 1 Do While n > 0 Fact = Fact * n n = n - 1 Loop End Function 修改: 方法一:在形参n前加ByVal 方法二:将调用语句中fact(i)改为fact( ( i ) ) 49
注 意 参数有两种传递方式:传值(ByVal)和传地址(ByRef)。 若调用时实参为常量或表达式,这两种方式没有区别,无论形参定义的是按值传递还是按地址传递,系统都是按传值方式传递 系统在调用时为形参分配一个临时存储单元,将表达式的值计算出来,存储到该临时单元;调用结束,系统收回临时单元。 调用函数或过程时,将单个变量转换成表达式的方法:将变量放在一对括号中。如用Fact((I))的方式调用函数,系统会按传值来处理。 50