第5章 使用过程.docx
《第5章 使用过程.docx》由会员分享,可在线阅读,更多相关《第5章 使用过程.docx(29页珍藏版)》请在冰豆网上搜索。
第5章使用过程
第5章使用过程
在开发VisualBasic应用程序时,通过工程(Project)来管理构成应用程序的所有不同的文件,VisualBasic的代码存储在不同的模块文件中。
在设计一个规模较大、功能较复杂的程序时,往往需要按功能将程序分解成若干个相对独立的部件,VisualBasic称这些部件为过程,对每个部件分别编写程序,可以简化程序设计任务。
VisualBasic工程文件(.vbp)包含了组成应用程序的所有窗体文件(.frm)、标准模块文件(.bas)、类模块文件(.cls)及其他文件,也包含环境设置方面的信息,如图5.1所示。
图5.1VB应用程序的结构
窗体模块、标准模块和类模块都可以包含声明和过程,它们形成了工程的一种模块层次结构,可以较好地组织工程,同时也便于代码的维护。
1.窗体模块(.frm)
每个窗体对应一个窗体模块,窗体模块包含窗体、控件的描述和属性设置,也含有窗体级的常数、变量、外部过程声明,以及事件过程和通用过程。
窗体模块保存在扩展名为.frm的文件中。
默认时应用程序中只有一个窗体,因此有一个以.frm为扩展名的窗体模块文件。
如果应用程序有多个窗体,就会有多个以.frm为扩展名的窗体模块文件。
添加新窗体的步骤是从“工程”菜单中执行“添加窗体”命令,则打开“添加窗体”对话框中的“新建”选项卡。
在该对话框中双击需要添加的窗体类型,新建的窗体将出现在工程窗口中。
2.标准模块(.bas)
简单的应用程序通常只有一个窗体,这时所有的代码都存放在该窗体模块中。
而当应用程序庞大而复杂时,就需要多个窗体。
在多窗体结构的应用程序中,有些程序员创建的通用过程需要在多个不同的窗体中共用,为了不在每个需要调用该通用过程的窗体重复键入代码,就需要创建标准模块。
标准模块保存在扩展名为.bas的文件中,缺省时应用程序中不包含标准模块。
标准模块可以包含常数、类型、变量和过程的声明,以及过程代码。
在工程中添加标准模块的步骤为:
(1)从“工程”菜单中执行“添加模块”命令,则打开“添加模块”对话框中的“新建”选项卡,如图5.2所示。
图5.2添加模块对话框图5.3新建标准模块窗口
(2)在该对话框中双击“模块”图标,将打开新建标准模块窗口,如图5.3所示。
(3)在属性窗口修改该模块的“名称”属性(只有此属性),给模块命令,接下来就是在标准模块的代码窗口中,向模块添加过程。
3.类模块(.cls)
类模块用于建立新对象,这些新对象可以包含自定义的属性和方法,类模块既包含代码又包含数据,它可以被应用程序内的过程调用。
实际上,窗体本身正是这样一种类模块,在其上可安放控件、可显示窗体窗口。
第1节Sub过程
Sub过程可以放在标准模块和窗体模块中,VisualBasic的Sub过程分为事件过程和通用过程两大类。
事件过程是当发生某个事件时,对该事件做出响应的程序段,它是VisualBasic应用程序的主体。
有时多个不同的事件过程可能需要使用同一段程序代码,为此,可将这段代码独立出来,编写成一个共用的过程,这种过程通常称为通用过程,它独立于事件过程之外,可供其他事件过程调用。
5.1.1事件过程
事件过程由VisualBasic自行声明,用户不能增加或删除。
当用户对某个对象发出一个动作时,Windows会通知VisualBasic产生了一个事件,VisualBasic会自动调用与该事件相关的事件过程。
事件过程是附加在窗体和控件上的,通常总是处于空闲状态,直到响应用户引发的事件或系统引发的事件才被调用。
1.窗体事件过程
窗体事件过程定义为“Form_事件名”,其格式为:
PrivateSubForm_<事件名>([参数表])
[语句组]
EndSub
不管窗体名字如何定义,但在事件过程中只能使用Form,而在程序中对窗体进行引用才会用到窗体名字。
如果正在使用MDI(MultipleDocumentInterface)窗体,则事件过程定义为“MDIForm_事件名”。
例如,运行程序后,单击窗体即会隐藏(窗体名称设为FormHide)的代码为:
PrivateSubForm_click()
FormHide.Show
Hide
EndSub
2.控件事件过程
控件事件过程的定义是“控件名_事件名”,其格式为:
PrivateSub<控件名>_<事件名>([参数表])
[语句组]
EndSub
例如,一个命令按钮的单击事件过程代码如下:
PrivateSubCommand1_Click()
Text1.Text="你好!
"
EndSub
在代码编辑器窗口建立事件过程,代码窗口会自动显示VisualBasic的保留字,这样可以看出哪些是自己的编码。
打开代码编辑器窗口有以下几种方法:
∙在设计窗体上双击窗体或控件,就打开了代码编辑器窗口,并会出现该窗体或控件的默认过程代码。
∙单击工程资源管理器窗口的“查看代码”按钮,再从对象列表框中选择一个对象,从过程列表框中选择一个过程。
∙可以自己编写事件过程,在代码编辑器窗口中直接编写事件过程。
在代码窗口中不要随意改变事件或对象名称,如果想改变对象名称,则应该通过属性窗口来改变。
5.1.2创建通用过程
当几个不同的事件过程要执行同样的动作,为了不必重复编写代码,可以采用通用过程来实现,由事件过程调用通用过程。
通用过程既可保存在窗体模块中,也可以保存在标准模块中。
通常一个通用过程并不和用户界面中的对象联系,通用过程直到被调用时才起作用。
因此,事件过程是必要的,但通用过程不是必要的,只是为了程序员方便而单独建立的。
通用过程与事件过程不同,通用过程并不是由对象的某种事件激活,也不依附于某一对象,故其创建的方法略有区别。
建立通用过程有两种方法:
直接在代码编辑窗口中输入过程代码、或使用添加过程对话框。
1.在代码编辑窗口中输入
在代码编辑窗口中,把光标定位在已有过程的外面,然后直接输入通用过程代码。
其语法格式为:
[Private|Public][Static]Sub<过程名>([参数表])
[语句列]
[ExitSub]
[语句列]
EndSub
说明:
(1)Private和Public:
用来声明该Sub过程是私有的(局部的),还是公有的(全局的)。
系统默认为Public,即可在应用程序中随意调用它们。
但如果声明为Private,则只有该过程所在模块中的程序才能调用该过程。
(2)Static:
静态变量声明。
如果使用Static关键字,则该过程中的所有局部变量的存储空间只分配一次,且这些变量的值在整个程序运行期间都存在,即在每次调用该过程时,各局部变量的值一直存在。
如果省略Static,过程每次被调用时重新为其变量分配存储空间,当该过程结束时释放其变量的存储空间。
(3)过程名:
与变量名的命名规则相同。
在同一模块中,同一过程不能既用于Sub过程,又用于Function过程。
(4)参数表:
类似于变量声明,它指明了调用过程传递给过程的变量个数和类型,称为形式参数(简称形参),各变量之间用逗号隔开。
形参并不代表一个实际存在的变量,也没有固定的值,在调用此过程时它被一确定的值所代替。
形参的格式为:
[[Optional][ByVal|ByRef]|ParamArray]<变量名>[()][As<类型>]
这里的Optional表示参数不是必需的关键字。
如果使用了该选项,则参数表中的后续参数都必须是可选的,而且必须都使用Optional关键字声明。
如果使用了ParamArray,则任何参数都不能使用Optional。
ByVal表示该参数按值传递,ByRef表示该参数按地址传递,ByRef是VisualBasic的缺省选项。
ParamArray只用于参数表的最后一个参数,指明最后这个参数是一个Variant元素的Optional数组。
使用ParamArray关键字可以提供任意数目的参数。
ParamArray关键字不能与ByVal,ByRef或Optional一起使用。
<变量名>代表参数的变量的名称,遵循标准的变量命令约定。
如果是数组变量,要在数组名后加上一对小括号。
<类型>代表传递给该过程的参数的数据类型,可以是Byte,Boolean,Integer,Long,Currency,Single,Double,Date,String(只支持变长),Object或Variant。
如果没有选择参数Optional,则可以指定用户定义类型或对象类型。
(5)语句列:
是VisualBasic的程序段,称为子程序体或过程体。
在执行语句列时,可以使用ExitSub从Sub过程中退出,以便执行该过程后续语句。
(6)EndSub:
用于结束本Sub过程。
(7)在过程内不能再定义过程,但可以调用其他过程。
例如,可直接在代码编辑器中输入:
Subwarning()
Text1.Text="警告"
EndSub
2.使用添加过程对话框
使用添加过程对话框建立过程的步骤为:
(1)打开要添加过程的代码编辑窗口。
(2)选择“工具”菜单的“添加过程”命令,打开“添加过程”对话框,如图5.4所示。
(3)在“名称”文本框中输入过程名,如Warning。
从“类型”选项组中选择过程类型,如“子程序”。
从“范围”选项组中选择范围,相当于使用Public或Private关键字,如选择“公有的”。
图5.4添加过程
单击“确定”按钮后,则在代码编辑器窗口中就创建一个名为Warning的过程代码:
PublicSubWarning()
EndSub
5.1.3通用过程的调用
要执行一个过程,必须调用该过程。
每次调用过程都会执行Sub和EndSub之间的语句列。
Sub过程的调用有两种方式:
Call<过程名>([参数表])
或
<过程名>[参数表]
说明:
(1)参数表:
在调用语句中的参数称为实际参数(简称实参),实参可以是变量、常数、数组和表达式。
参数与参数之间要用逗号隔开。
(2)使用Call语句调用时,参数必须放在括号内,当被调用过程没有参数时,则()也可省略。
(3)用过程名调用时,过程名后不能加括号,若有参数,则参数直接跟在过程名之后,参数与过程名之间用空格隔开,参数与参数之间用逗号分隔。
例如,对过程SubStars1()与SubStars2(m)可采用如下方式调用:
CallStars1
Stars1
CallStars2(20)
Stars220
在大多数情况下,通常是在事件过程中调用过程。
但由于事件过程也是过程(Sub过程),因此也可以被其他过程调用。
【例5.1】求S=5!
+7!
+9!
的值。
分析:
要计算S=5!
+7!
+9!
,先要分别计算出5!
,7!
和9!
。
由于3个求阶乘的运算过程完全相同,因此可以用通过SubFact过程来计算任意阶乘n!
,每次调用Fact过程前给n一个值,在Sub过程中将所求结果放入到total变量中,返回主程序后tot变量接收total的值。
这样3次调用子程序便可求得S。
Fact通用过程为:
SubFact(ByValnAsInteger,totalAsLong)
DimiAsInteger
total=1
Fori=1Ton
total=total*i
Nexti
EndSub
命令按钮的Click事件代码为:
PrivateSubCommand1_Click()
Dima,b,cAsInteger
DimtotAsLong
a=5:
b=7:
c=9
CallFact(a,tot)
s=tot
CallFact(b,tot)
s=s+tot
Factc,tot
s=s+tot
Text1.Text=s
EndSub
单击命令按钮,运行结果如图5.5所示。
图5.5计算阶乘法结果
第2节Function过程
函数是过程的另一种形式,当过程的执行返回一个值时,使用函数就比较简单。
VisualBasic包含了许多内部的函数,如sin,date,chr等。
用户在编写程序时,只需写出一个函数名并给定参数就能得出函数值。
当在程序中需要多次用到某一公式或要处理某一函数关系,而又没有现成的内部函数可使用时,VisualBasic允许使用Function语句编写用户自定义的Function(函数)过程。
5.2.1Function过程的定义
与Sub过程一样,Function过程也是一个独立的过程,可读取参数、执行一系列语句并改变其参数的值。
与Sub过程不同的是,Function过程可返回一个值到调用的过程。
Function过程的格式为:
[Private|Public][Static]Function<函数名>([参数表])[As<类型>]
[语句列]
[函数名=表达式]
[ExitFunction]
[语句列]
[函数名=表达式]
EndFunction
说明:
(1)As<类型>:
函数返回值的数据类型,与变量一样,如果没有As子句,默认的数据类型为Variant。
(2)ExitFunction语句:
用于提前从Function过程中退出,程序接着从调用该Function过程语句的下一条语句继续执行。
在Function过程的任何位置都可以有ExitFunction语句。
但用户退出函数之前,应保证为函数赋值,否则会出错。
(3)函数名=表达式:
在函数体中用该语句给函数赋值,如果在Function过程中默认该语句,则该Function过程的返回值为数据类型的默认值。
例如,数值函数返回值为0,字符串函数返回值为空字符串。
(4)和Sub过程一样,Function过程不能嵌套定义,但可以嵌套调用。
例如,下面是计算直角三角形第三边(斜边)的函数,函数名为Hypotenuse,数据值的数据类型为Integer,函数的形参为直角三角形两直角边A和B,返回值为斜边的值,Function过程代码如下:
FunctionHypotenuse(AAsInteger,BAsInteger)AsInteger
Hypotenuse=Sqr(A^2+B^2)
EndFunction
与Sub过程一样,既可以直接从代码编辑窗口中输入过程代码,也可以使用添加过程对话框来定义Function过程。
由于函数具有返回值,还需对系统自动产生的函数过程进行适当的修改,即在过程名后面加上对其返回值类型的定义和说明。
5.2.2Function过程的调用
调用函数Function过程的方法和调用VisualBasic内部函数方法一样,在语句中直接使用函数名,Function过程可返回一个值到调用的过程。
其格式为:
Function函数名([参数表])
例如,下面的代码调用了计算直角三角形斜边的Function过程:
Text1.Text=Hypotenuse(3,4)
另外,采用调用Sub过程的语法也能调用Function函数。
当用这种方法调用函数时,放弃函数的返回值。
例如,下面的代码调用了同一个Function过程:
CallHypotenuse(3,4)
Hypotenuse3,4
函数可以没有参数,在调用无参函数时不发生虚实结合。
调用无参函数得到一个固定的值,如下述无参函数:
FunctionFA1()
FA1="我们的任务完成了!
"
EndFunction
【例5.2】用函数调用编写求两个自然数的最大公约数的程序。
分析:
求最大公约数可以用“辗转相除法”,方法如下:
(1)以大数m做被除数,小数n做除数,相除后得余数r。
(2)若r≠0,则m←n,n←r,继续相除得到新的r。
若仍有r≠0,则重复此过程,直到r=0为止。
(3)最后的n就是最大公约数。
根据此算法,首先设计一个求两个自然数最大公约数的Function过程Divisor,如下:
FunctionDivisor(ByValxAsInteger,ByValyAsInteger)AsInteger
Dimr,cAsInteger
Ifxc=x:
x=y:
y=c
EndIf
r=xMody
DoWhiler<>0
x=y
y=r
r=xMody
Loop
Divisor=y
EndFunction
应用程序的用户界面设置如图5.6所示。
命令按钮的Click事件代码为:
PrivateSubCommand1_Click()
Dimm,nAsInteger
m=Val(Text1.Text)
n=Val(Text2.Text)
Ifm*n=0ThenExitSub
Label1.Caption="自然数"&Str(m)&"和"&_
Str(n)&"的最大公约数是:
"&Str(Divisor(m,n))
EndSub
图5.6求最大公约数
在Text1和Text2中输入两个整数m和n,单击Command1_Click事件,调用Divisor函数,m和n传递给Divisor函数,Divisor函数计算的结果返回给Command1_Click事件过程,并将结果显示在Label1中。
第3节参数传送
调用过程时可以把数据传递给过程,也可以把过程中的数据传递回来。
在调用过程时,需考虑调用过程和被调用过程之间的数据是如何传递的。
通常在编制一个过程时,应考虑需要输入哪些数据,进行处理后输出哪些数据。
正确地为一个过程提供输入数据和正确地引用其输出数据,是使用过程的关键,也就是调用过程和被调用过程之间的数据传递问题。
在调用一个有参数的过程时,首先进行的是形参与实参的结合,实现调用过程的实参与被调用过程的形参之间的数据传递,数据传递有两种方式:
按值传递和按地址传递。
5.3.1形参与实参
在被调用过程中的参数是形参,出现在Sub过程和Function过程中。
在过程被调用之前,形参并未被分配内存,只是说明形参的类型和在过程中的作用。
形参列表中的各参数之间用逗号分隔,形参可以是变量名和数组名,但不能是定长字符串变量。
实参是在主调过程中的参数,在过程调用时实参将数据传递给形参。
实参表可由常量、表达式、有效的变量名、数组名组成,实参表中各参数用逗号分隔。
在调用过程时,实参被插入形参中的各变量处进行“形实结合”,形实结合是按位置结合的,即第一个实参与第一个形参结合,第二个实参与第二个形参结合,依此类推。
例如:
形参列表和实参列表中的对应变量名可以不同,但实参和形参的个数、顺序以及数据类型必须相符。
所谓类型相符,对于变量参数就是类型相同,对于值参数则要求实际参数对形式参数赋值相容。
若在过程的形参表中列入了Optional关键字,则可以指定过程的形式参数为可选参数。
如果某一参数为可选参数,则参数表中此参数后面的其他参数也必须是可选的,并要用Optional来声明。
例如,我们建立一个计算两个数据的乘积的过程,它能可选择地乘以第三个数。
在调用时,既可以给它传递两个参数,也可给它传递3个参数。
为了定义带可选参数的过程,必须在参数表中使用Optional关键字,并在过程体中通过IsMissing函数来测试调用时是否传递可选参数。
过程代码为:
SubMulti(firAsInteger,secAsInteger,Optionalthir)
n=fir*sec
IfNotIsMissing(thir)Then
n=n*thir
EndIf
Printn
EndSub
在调用上面的过程时,可以提供两个参数,也可提供3个参数,都能得到正确的结果。
例如,如果用下述事件过程调用:
PrivateSubForm_Click()
Multi10,20
EndSub
结果为200。
如果用下述过程调用:
PrivateSubForm_Click()
Multi10,20,30
EndSub
结果为6000。
上述过程只有一个可选参数,也可以有两个或多个。
但应注意,可选参数必须在参数的最后,且一般为Variant类型。
另外,还可给可选参数指定缺省值,如Multi过程可改为:
SubMulti(firAsInteger,secAsInteger,OptionalthirAsInteger=30)
……
EndSub
一般来说,过程调用中的参数个数应等于过程说明的参数个数。
如果使用ParamArray关键字,则过程可以接受任意个数的参数。
例如,我们可以定义一个可变参数过程,用这个过程可以求任意多个数的乘积。
SubMulti(ParamArrayNumbers())
n=1
ForEachxInNumbers
n=n*x
Nextx
Printn
EndSub
可以用任意个参数调用上述过程,如:
PrivateSubForm_Click()
Multi3,4,5,6,7
EndSub
输出结果为2520。
5.3.2值传递与地址传递
传递参数的方式有两种:
如果调用语句中的实际参数是常量或表达式,或定义过程时选用ByVal关键字,就可以按值传递。
如果调用语句中实际参数为变量,或定义过程时选用ByRef关键字,就可以按地址传递。
1.按值传递参数
按值传递参数时,VisualBasic给传递的形参分配一个临时的内存单元,将实参的值传递到这个临时单元去。
实参向形参传递是单向的,如果在被调用的过程中改变了形参值,则只是临时单元的值变动,不会影响实参变量本身。
当被调用过程结束返回主调过程时,VisualBasic将释放形参的临时内存单元。
当要求变量按值传递时,可以先把变量变成一个表达式,把变量转换成表达式的最简单的方法就是把它放在括号内。
例如把变量“A”用括号括起来,“(A)”就成为一个表达式了。
或者定义过程时用ByVal关键字指出参数是按值来传递的。
【例5.3】用函数过程编写程序,求a,b两数中最大数。
Max函数为求最大数,在Command1_click中调用Max函数,程序代码如下:
PrivateFunctionMax(ByValxAsInteger,ByValyAsInteger)
DimzAsInteger
Ifxx=y:
y=z
Max=x
TextX.Text=x
TextY.Text=y
EndFunction
PrivateSubCommand1_Click()
DimaAsInteger,bAsInteger,cAsInteger
a=Val(TextA.Text)
b=Val(TextB.Text)
TextMax.Text=Max(a,b)
TextRA.Text=a
TextRB.Text=b
EndSub
在文本框中输入变量a为25、b为36,单击“计算”按钮,程序运行结果如图5.7所示。
图