版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第9章
过程子程序过程函数过程参数传递可选参数与可变参数对象作参数9.1子程序过程子程序过程由Sub…EndSub定义,也称为Sub过程。9.1.1Sub过程的定义定义Sub过程的一般格式如下:用上面的格式定义一个Sub过程如下:[Static][Public][Private]Sub过程名[(参数列表)]
局部变量或常量定义
语句块 [ExitSub] [语句块] EndSubPrivateSubTest()Print"ThisisaSubexample"EndSubSub过程以Sub开头,以EndSub结束,在它们之间是描述该过程操作的语句块,称为过程体或子程序体。上面定义格式中各选项的含义如下:Static:指定过程中的局部变量都是静态变量,即在每次调用该过程时,局部变量的值保持不变。Public:表示该Sub过程是公有过程,即可以在程序的任何地方调用它。Private:表示该Sub过程是私有过程,即只能被本模块中的其他过程访问,不能被其他模块中的过程访问。过程名:是一个长度不超过255个字符的变量名,在同一个模块中,不允许变量名与过程名同名。参数列表:指明了在调用该过程时传送给过程的参数的类型和个数,这些参数称为“形式参数”,简称“形参”。各参数之间以逗号分隔,每个参数的定义格式为:
其中,ByVal是可选的,如果有ByVal,表示该参数是“传值参数”,不加ByVal的参数称为“引用参数”。[ByVal]变量名[()][As数据类型]Sub过程不能嵌套,也就是说,在Sub过程内不能再定义Sub过程或函数过程。不能用GoTo语句进入或跳出一个Sub过程,只能通过调用执行Sub过程,Sub过程的调用可以嵌套。下面再看一个Sub过程的例子:该Sub过程有两个形参,其中第二个形参前面有ByVal,表示该参数是一个传值参数。SubTry(xAsInteger,ByValyAsInteger) x=x+100 y=y*5 Printx,y EndSub再看一个无参的Sub过程:
SubTest() Do Response$=InputBox$("Continue(YorN)?") IfResponse$="N"OrResponse$="n"ThenEnd IfResponse$="Y"OrResponse$="y"ThenExitDo Loop EndSub9.1.2Sub过程的建立前面我们已学会如何建立事件过程,Sub过程不属于任何一个事件过程,因此不能放在事件过程中。Sub过程是一个通用过程,可以在标准模块中建立,也可以在窗体模块中建立。在标准模块中建立通用过程的步骤如下:(1)选择“工程”菜单中的“添加模块”命令,打开“添加模块”对话框,在该对话框中选择“新建”选项卡,然后双击“模块”图标,打开模块代码窗口。(2)选择“工具”菜单中的“添加过程”命令,打开“添加过程”对话框,如右图所示。在“名称”框内输入要建立的过程的名字,在“类型”框内选择要建立的过程的类型:子程序过程或函数过程,在“范围”框内选择过程的适用范围。(3)单击“确定”按钮,回到模块代码窗口,此时可以在Sub和EndSub之间键入程序代码。“添加过程”对话框9.1.3Sub过程的调用可以把Sub过程的调用当作是一句独立的调用语句,可以有两种调用形式:
或
前者用Call关键字,若有实参,必须用小括号括起来,无实参时小括号可省略;而后者去掉了关键字Call,并且实参不需要用小括号括起来。实参也称实际参数,是在过程被调用时写在过程名后面括号中的参数。且实参的数据类型必须与定义过程时的形式参数一致。它的作用是把需要实际运算的数据传递给形式参数。如调用前面定义的Sub过程Try时,可用:
或
Call过程名[(实参表列)]过程名[实参表列]CallTry(a,b)Try
a,b例9.1
编写一个计算矩形面积的Sub过程,然后调用该过程求一个矩形的面积。程序代码如下:SubArea(x,y)DimSS=x*yMsgBox"Areais"&SEndSubSubForm_Click()DimA,BA=InputBox("Inputthelength:")A=Val(A)B=InputBox("InputtheWidth:")B=Val(B)CallArea(A,B)'或:AreaA,BEndSub程序运行时,单击窗体,首先出现一个输入对话框,要求输入矩形的长,假设输入30,确定后又出现一个输入对话框,要求输入矩形的宽,假设输入20,确定后出现运行结果如下图所示。调用Sub过程求矩形的面积9.2函数过程函数过程由Function…EndFunction定义,也称为Function过程。与Sub过程相比,Sub过程不直接返回值,作为独立的基本语句调用,而Function过程要返回一个值,通常在一个表达式中被调用。9.2.1Function过程的定义Function过程的定义格式如下:
其中:[As类型]可选项是Function过程返回的值的数据类型,可以是Integer、Long、Single、Double、Currency或String。如果省略,默认为Variant类型。其他各选项与Sub过程相同。[Static][Public][Private]Function过程名[(参数列表)][As类型]
局部变量或常量定义
语句块 [过程名=表达式] [ExitFunction] [语句块] EndFunction把某功能定义为Sub过程还是Function过程,没有严格的规定,但Function过程有返回值。定义Function过程时,要定义返回值的数据类型,同时在Function过程体内可以对Function过程名赋值,该值就是这个函数的返回值。如果在Function过程体内省略:
则该Function过程返回一个默认值(0或空字符串)。例如,要编写用辗转相除法求最大公约数的函数,程序如下:过程名=表达式Functiongcd(ByValxAsInteger,ByValyAsInteger)AsInteger DoWhiley<>0 r=xMody x=y y=r Loop gcd=xEndFunction9.2.2Function过程的调用由于Function过程能返回一个值,因此完全可以把Function过程当做内部函数调用,只不过内部函数由系统提供,而Function过程由用户自己定义。例如,上面的Function过程gcd,可以在下面的事件过程中调用。例9.2调用后,例9.2程序的运行结果如下图所示。SubForm_Click() DimaAsInteger,bAsInteger a=64:b=48 f=gcd(a,b) Print"最大公约数为:";fEndSub调用Function过程例9.3
分别编写一个计算下列级数和的子过程和函数过程,并分别调用。1+x+x2/2!+…+xn/n!+…精确到|xn/n!|<eps(eps由用户给定)子过程如下:Subsum1(s#,x!,eps#)Dimn%,t#n=1:s=0:t=1DoWhile(Abs(t)>=eps)s=s+tt=t*x/nn=n+1LoopEndSub函数过程如下:Functionsum2(x!,eps#)AsDoubleDimn%,s#,t#n=1:s=0:t=1DoWhile(Abs(t)>=eps)s=s+tt=t*x/nn=n+1Loopsum2=sEndFunction用下面的事件过程调用:PrivateSubCommand1_Click()Dimf1#,f2#Callsum1(f1,2#,0.000001)f2=sum2(2#,0.000001)Print"f1=";f1,"f2=";f2EndSub在窗体中添加一个命令按钮Command1,程序运行时单击该命令按钮,则运行结果如下图所示。其中f1是调用子过程sum1求得的级数和,f2是调用函数过程sum2求得的级数和。子过程和函数过程的比较9.3参数传递在调用一个过程时,一般主调过程与被调过程之间有数据传递,也就是要把主调过程的实参传递给被调过程的形参,完成实参与形参的结合,然后执行被调过程体。在VB中,实参与形参的结合有两种方法:传值(ByVal)和传址(ByDef)。9.3.1传值和传址传址又称为引用,是默认的参数传递方法。区分两种传递方法是看形参前有无“ByVal”关键字。传址的结合过程是:当调用一个过程时,将实参的内存地址传递给形参。因此在被调过程体中对形参的操作实际是对相应实参的操作,实参的值就会随过程体内对形参的值的改变而改变。传址习惯上也称为“引用”。传值的结合过程是:当调用一个过程时,系统将实参的值复制给形参,实参与形参各自占用不同的内存单元,过程调用结束时,形参所占的内存单元也同时被释放。因此,在过程体内对形参的操作不会影响到实参。例9.4
传址与传值的比较。有如下过程:SubTry(xAsInteger,ByDefyAsInteger)'第二个参数中的ByDef关键字可以省略 DimtempAsInteger temp=x x=y y=temp Form1.Print"x=";x,"y=";yEndSub在下面的事件过程中调用上述过程:
运行程序,单击窗体,输出结果如下图所示。由此可以看到,在过程Try中交换了两个形参的值,调用结束返回事件过程后,两个实参的值也被改变了。SubForm_Click() DimaAsInteger,bAsInteger a=10:b=20 Print"a=";a,"b=";b Trya,b Print"a=";a,"b=";bEndSub传址调用如果不想改变实参的值,可将过程Try修改如下:仍旧用上面的Form_Click()事件过程去调用,则窗体上的输出结果如下图所示。可以看到形参的值的改变没有影响实参。SubTry(ByValxAsInteger,ByValyAsInteger) DimtempAsInteger temp=x x=y y=temp Form1.Print"x=";x,"y=";yEndSub传值调用我们已经知道,用Function过程可以通过过程名返回值,但一个Function过程只能返回一个值。Sub过程不能通过过程名返回值,但可以通过传址结合的参数返回值,并且可以返回多个值,请看下面的例子。例9.5
通过传址调用Sub过程,返回多个值。程序如下:SubS(ByValxAsInteger,ByValyAsInteger,mAsInteger,nAsInteger)m=x+yn=x*yEndSubPrivateSubForm_Click()DimSumAsInteger,MulAsIntegerS10,20,Sum,MulPrintSum,MulEndSubSub过程S有4个参数,前两个参数用关键字ByVal指明是传值调用,后两个参数m和n前面没有关键字,则是默认的传址方式。在Form_Click()事件过程中调用Sub过程S的语句为:则将10和20分别传值给形参x和y,将实参Sum和Mul的地址传递给形参m和n,即m与Sum占用同一段内存,n与Mul占用同一段内存,因此在过程S中将x+y、x*y的值分别赋给m、n,也就是将这两个值分别存入了Sum和Mul所占的内存单元中。于是调用完过程S返回Form_Click()事件过程中输出Sum和Mul的值时,将输出:
S10,20,Sum,Mul30 2009.3.2数组作参数传递在VB中允许把数组作为实参传递给一个过程。这时,应将数组名分别放入实参表和形参表中,并略去数组的上下界,但数组名后的小括号不能省,以免与普通变量混淆。数组只能通过传址方式进行传递,也就是说,用数组作过程参数时,可以将实参数组的全部元素传送给一个过程,而形参数组中各元素的改变将被带回到实参数组。例9.6
编写一个Function过程,求数组的最大值。PrivateFunctionFindMax(a()AsInteger)DimStartAsInteger,FinishAsInteger,iAsIntegerStart=LBound(a)Finish=UBound(a)Max=a(Start)Fori=StartToFinishIfa(i)>MaxThenMax=a(i)NextiFindMax=MaxEndFunctionSubForm_Click()ReDimb(10)AsIntegerFori=1To10t=InputBox("inputInteger:")b(i)=tNextic=FindMax(b())PrintcEndSub程序中定义了一个函数过程FindMax,它有一个形参,即数组a。当在Form_Click()事件过程中调用函数过程FindMax时,将实参数组b作参数传递给形参数组a,于是,形参数组a与实参数组b共占同一段内存空间。而且因为两个数组类型相同,因此a(i)就是b(i)的值。接下来在函数过程FindMax中用LBound和Ubound函数分别求得数组a的下界和上界,然后对数组中元素进行比较,找到数组a的最大值,其实也就是数组b中所有元素的最大值,通过函数过程FindMax,将此最大值返回给Form_Click()事件过程并输出。有时不需要把整个数组传送给通用过程,可以只传送所需要的某个元素,只要在实参数组名后的小括号内写上要传送的元素的下标。这时,形参不需要定义成数组,只要定义成与作实参的数组元素同类型的变量即可。这种用法其实与前面介绍的传值或传址调用类似。例9.7
用二维数组的某个元素作实参调用一个Sub过程。程序代码如下:Dimtest_array()AsIntegerStaticSubSqval(a)a=Sqr(Abs(a))EndSubSubForm_Click()ReDimtest_array(1To5,1To3)test_array(5,3)=-25Printtest_array(5,3)CallSqval(test_array(5,3))Printtest_array(5,3)EndSub程序中:CallSqval(test_array(5,3))语句把二维数组test_array中的元素test_array(5,3)作为实参传递给形参a,可以看到形参a是一个变量,并且实参与形参的结合是默认的传址方式。因此在调用过程Sqval时改变a的值,实参test_array(5,3)的值也随之改变。所以程序运行后,单击窗体,在窗体中显示输出结果为:最后还要说明一点:通过过程传送参数时,实参与对应的形参的类型应当一致。如果实参是数值常数或数值表达式,而它的类型与对应的形参的类型又不匹配时,则系统会将此数值常数或数值表达式强制转换为相应形参的类型。 -2559.3.3按位置传送和指名传送1.按位置传送按位置传送是大多数程序设计语言在子程序调用时所使用的参数传送方式,在前面的例子中使用的都是按位置传送。使用按位置传送时,实参的个数与形参的个数必须相等,而且实参的类型必须与相应的形参的类型相同,实参的名字与相应的形参的名字可以不同。也就是说,实参必须和形参表中同一位置的形参相匹配。如下面定义的一个过程:
SubTest(x1AsInteger,x2AsSingle,x3AsString) …… EndSub我们可以用下面的语句调用该过程:不难看出,实参a、b和"ABC"分别与对应位置上的形参x1、x2和x3类型相同,并且实参的个数与形参的个数也相同。在按位置传送时,实参可以是常数、合法的变量名、表达式或后面跟有左右括号的数组名。而形参表中的变量可以是除定长字符串之外的合法变量名或后面跟有左右括号的数组名。注意:只能使用形如Str$或StrAsString之类的变长字符串作为形参,不能用形如StrAsString*8之类的定长字符串作为形参,但定长字符串可以作实参传送给过程。 CallTest(a%,b!,"ABC")2.指名传送除按位置传送外,在VB中还提供了与Ada语言类似的参数传送方式,即指名参数传送方式。所谓指名传送方式,就是显式地指出与形参结合的实参,把形参用“:=”与实参连接起来。指名传送方式不受参数的位置次序的影响,但要求实参与形参的名字必须相同。如建立如下的过程:
使用按位置传送时,我们可以写出调用语句如下:SubTest(x1AsInteger,x2AsInteger,x3AsInteger) …… EndSub Test4,6,8如果使用指名传送方式,则下面的三个调用语句都是可以的:
并且这三个调用语句是完全等价的。使用指名传送比使用按位置传送在书写上繁琐,但指名传送能改善过程调用的可读性,而且,当参数较多,类型又相似时,指名传送比按位置传送出错的可能性要小一些。但应当注意的是,有些方法的调用是不能使用指名传送的。使用时可查阅相关的帮助信息。Testx1:=4,x2:=6,x3:=8Testx2:=6,x1:=4,x3:=8Testx3:=8,x2:=6,x1:=49.4可选参数与可变参数在VB中调用一个过程时,还可以向过程传送可选的参数或者任意数量的参数,即可选参数和可变参数。9.4.1可选参数在前面的例子中,如果一个过程有3个形参,则调用时必须按相同的顺序和类型提供3个实参。在VB中,还可以指定一个或多个参数作为可选参数,在调用时,可以不必给可选参数传递实参。为了定义带可选参数的过程,需要在可选参数名前加“Optional”关键字,并在过程体中通过IsMissing函数测试调用时是否给可选参数传递实参。例如:SubSum(aAsInteger,bAsInteger,Optionalc)n=a+bIfNotIsMissing(c)Thenn=n+cEndIfPrintnEndSub上述过程中有3个参数,前两个参数与前面例子中的参数相同,最后一个参数没有指定类型,默认其类型为Variant,它前面有一个关键字“Optional”,表示它是一个可选参数。在过程体中,首先计算前两个参数的和,并把结果赋值给变量n,然后用IsMissing函数测试第三个参数c是否存在,如果存在,则把第三个参数c的值也加到变量n中,最后将n的值输出。在调用上面的Sum过程时,可以传递两个实参,求出两个数的和,也可以传递三个实参,求出三个数的和。如用下面的事件过程调用上述的Sum过程:输出结果为: 30PrivateSubForm_Click()Sum10,20EndSub也可以用下面的过程调用:
输出结果为: 60上面的Sum过程只有一个可选参数,我们可以根据实际需要,用同样的方法设置两个或多个可选参数。但要注意:可选参数必须放在参数表列的最后,并且必须是Variant类型。PrivateSubForm_Click() Sum10,20,30 EndSub9.4.2可变参数所谓可变参数,就是在定义过程时参数的个数是可变的,这在处理一些问题时是非常有用的。这里的“数组名()”是一个形参,只有名字和括号,没有上、下界,其类型默认为Variant类型。在VB中,建立可变参数过程可用如下方式定义: Sub过程名(ParamArray数组名())
过程体 EndSub前面定义的Sum过程可以求两个或三个数的和。如果想求任意多个数的和,可定义一个可变参数过程Sum如下:
可以用任意多个实参调用上面的Sum过程。如编写下面的事件过程:用该事件过程调用上面的Sum过程,输出结果为: 15SubSum(ParamArrayNum()) n=0 ForEachxInNum n=n+x Nextx Printn EndSub PrivateSubForm_Click() Sum1,2,3,4,5 EndSub由于可变参数过程中的形参是Variant类型,因此我们可以把任何类型的参传送给该过程。看下面这个事件过程:
调用上面的Sum过程,输出结果为: 28PrivateSubForm_Click() DimaAsInteger,bAsLong,cAsVariant,dAsInteger a=6:b=8:c=12:d=2 Suma,b,c,d EndSub9.5对象作参数除了可以用变量作通用过程的形式参数外,在VB中还允许用对象(即窗体或控件)作通用过程的参数。用窗体或控件作形参时,过程的定义格式与用变量作参数相同。只不过是把形参表中的对象参数的类型定义为“Control”或“Form”。但要注意,在调用含有对象参数的过程时,对象参数只能用传地址方式传送。也就是说,在定义过程时不能在对象参数前加关键字ByVal。9.5.1窗体参数假设我们要设计一个程序,在这个程序中含有多个窗体(关于多窗体的程序设计,我们将在后面章节介绍),而且要求在运行程序时,这些窗体的位置、大小都相同。我们知道,窗体的位置和大小可以通过窗体的Left、Top、Width及Height四个属性来设置。假定这些窗体的名字分别为Form1、Form2、Form3…,我们可以写出下面的程序段:
…… Form1.Left=2000 Form1.Top=3000 Form1.Width=5000 Form1.Height=3000Form2.Left=2000 Form2.Top=3000 Form2.Width=5000 Form2.Height=3000
Form3.Left=2000 Form3.Top=3000 Form3.Width=5000 Form3.Height=3000 ……每个窗体都要用四个语句来确定其大小和位置。这四个语句除窗体名不同外,其他都是一样的。因此,为了避免这些语句的重复书写,我们可以用窗体作参数,编写出如下的通用过程:
该过程的形参即为一个窗体类型。在调用时,就可以用窗体作实参。例如可以用如下的语句调用上述过程:
则将按过程中给出的各属性值设置窗体Form1的大小和位置。SubFormSet(FormNumAsForm) FormNum.Left=2000 FormNum.Top=3000 FormNum.Width=5000 FormNum.Height=3000 EndSubFormSetForm1为了调用上面的通用过程FormSet,可以选择“工程”菜单中的“添加窗体”命令建立多个窗体,现假设我们建立4个,即Form1、Form2、Form3和Form4。在默认情况下,第一个建立的窗体(这里假设是Form1)是启动窗体。我们对Form1编写如下的事件过程:
PrivateSubForm_Load() FormSetForm1 FormSetForm2 FormSetForm3 FormSetForm4 EndSub然后对4个窗体分别编写如下的Click事件过程:
PrivateSubForm_Click() Form1.Hide'窗体Form1隐藏 Form2.Show'显示窗体Form2 EndSub PrivateSubForm_Click() Form2.Hide Form3.Show EndSub
PrivateSubForm_Click() Form3.Hide Form4.Show EndSubPrivateSubForm_Click() Form4.Hide Form1.Show EndSub于是,在运行程序时,首先显示Form1,单击该窗体后,Form1隐藏,显示Form2;单击Form2窗体后,Form2隐藏,Form3显示出来……,每个窗体显示的大小和位置均相同。9.5.2控件参数和窗体参数一样,控件也可以作通用过程的参数,即可以在一个通用过程中设置相同性质的控件所需要的属性,然后用不同的控件作实参调用该过程。请看下面这个例子。例9.8
在窗体上建立两个文本框,然后编写一个通用过程,用控件作参数,用来设置文本框中显示的字体属性。通用过程如下:
SubFontSet(Ctrl1AsControl,Ctrl2AsControl) Ctrl1.FontSize=18 Ctrl1.FontName=“幼圆” Ctrl1.FontItalic=True Ctrl1.FontBold=True Ctrl1.FontUnderline=FalseCtrl2.FontSize=26 Ctrl2.FontName=“隶书” Ctrl2.FontItalic=False Ctrl2.FontUnderline=True EndSub该过程有两个参数,其类型均为Control,即控件参数。在该过程中通过一系列语句设置了控件上所显示的文字的属性。为了调用该过程,我们在窗体上建立两个文本框,然后编写如下的事件过程:
PrivateSubForm_Load() Text1.Text=“欢迎来到” Text2.Text=“新乡师专计科系” EndSub
PrivateSubForm_Click() FontSetText1,Text2 EndSub
程序运行后,窗体显示如左图所示,然后单击窗体,运行结果如右图所示。对象参数示例
对象作参数改变文本框字体在使用控件作参数时,由于不同的控件所具有的属性也不一样,因此,在用指定的控件作实参调用通用过程时,如果通用过程中
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025工程发包合同范文
- 劳务合同范例一
- 公墓转让合同范例
- 北京家具销售合同范例
- 个人收购大蒜合同范例
- 2014建设合同范例
- 传媒设备公司合同范本
- 中标服务合同范本
- 农村养殖农户合作合同范例
- 出租房门窗合同范本
- 2024-2025学年成都市金牛区九年级上期末(一诊)英语试题(含答案)
- 2025年高压电工资格考试国家总局模拟题库及答案(共四套)
- 2024-2025学年广东省深圳市南山区监测数学三年级第一学期期末学业水平测试试题含解析
- 格式塔心理学与文艺心理学
- (汽车制造论文)机器人在汽车制造中应用
- 幼儿园手工教学中教师指导行为研究-以自贡市幼儿园为例
- 初中物理实验教学
- 《智能投顾 大数据智能驱动投顾创新》读书笔记思维导图
- 企业应急管理及能力提升培训课件精选
- 吲哚菁绿血管造影检查知情同意书
- 最新婚姻家庭心理讲座主题讲座课件
评论
0/150
提交评论