《Visual Basic程序设计教程(第二版)》课件6_第1页
《Visual Basic程序设计教程(第二版)》课件6_第2页
《Visual Basic程序设计教程(第二版)》课件6_第3页
《Visual Basic程序设计教程(第二版)》课件6_第4页
《Visual Basic程序设计教程(第二版)》课件6_第5页
已阅读5页,还剩65页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第1章过程【本章导读】

在VisualBasic中有一类过程属于自定义过程,它由用户建立,供事件过程或其他自定义过程调用。每个自定义过程都具有独立的功能,自定义过程的使用符合结构化程序设计的原则,它的好处是使程序简练、便于调试和维护。这一章我们主要介绍自定义过程的设计和使用。在VisualBasic中,根据是否有返回值,把自定义过程分为两类:子过程和函数过程。第1章VisualBasic程序设计概述【本章要点】

面子过程的建立和使用函数过程的建立和使用过程中参数的传递变量和过程的作用域过程的递归和嵌套

Sub(子程序)过程可以描述两种过程:事件过程和通用过程。

表示窗体事件或控件事件的格式:

PrivateSubForm|控件名_事件名(参数列表)

<语句组>

EndSub6.1.1事件过程和通用过程1.事件过程建立方法:1.手工键入。

2.使用模板。2.通用过程

通用过程是独立于事件过程之外,不与任何特定的事件相联系,它可以存储在窗体模块或标准模块中。6.1子过程一般格式:

[Static][Private|Public]Sub过程名[(参数表列)]

语句块

[ExitSub][语句块]EndSub6.1.2建立Sub过程1.定义Sub过程说明:(1)Sub过程以Sub开头,以EndSub结束,在它们之间是描述过程操作的语句块,称为“过程体”或“子程序体”。格式中各参量的含义如下:Static:指定过程中的局部变量在内存中的存储方式。如果使用了

Static,则过程中的局部变量就是“静态”变量。

Private|Public

:表示Sub过程是私有过程或公有过程。过程名:是一个长度不超过40个字符的变量名,命名规则与变量名规则相同。参数表列:含有在调用时传送给过程的简单变量名或数组名,各名字之间用逗号隔开。“参数表列”指明了调用时传送给过程的参数的类型和个数,每个参数的格式为:

[ByVal][Byref]变量名[()][As数据类型]

如果加上“ByVal”,则表明该参数是“传值”参数,没有加“ByVal”(或者加ByRef)的参数称为“传址”参数。数据类型为前面介绍的。

说明:(2)EndSub标志着Sub过程的结束。当程序执行到EndSub时,将退出该过程,并立即返回到调用语句下面的语句。此外,在过程体内可以用一个或多个ExitSub语句从过程中退出。(3)Sub过程不能嵌套定义。说明:

例:编一个交换两个整型变量值的子过程。

PrivateSubSwap(XAsInteger,YAsInteger)DimtempAsIntegerTemp=X:X=Y:Y=TempEndSub

(1)利用工具中“添加过程”对话框定义。

2.创建Sub过程(2)直接在代码窗口定义

打开模块代码窗口,然后直接键入

过程的名字即可。例:键入“SubTestProc”,按回车键后就会自动显示:

SubTestProc()

EndSub

1.用Call语句调用Sub过程格式:Call过程名[(实际参数)]

例如:CallTestProc(a,b)2.把过程名作为一个语句来使用

格式:过程名[实际参数]

例如:TestProca,b6.1.3调用Sub过程第二种方式与第一种方式相比,它有两点不同:(1)去掉关键字call。(2)去掉“实际参数”的括号。Sub过程示例【例6.1】编写交换两个数的子过程,并调用该过程交换a和b,c和d两组变量的值。分析:首先要编写一个交换两个数的过程。我们把两个数分别放入两个变量中,交换两个数时要引入第三个变量t,先把第一个数放在t中,然后把第二个变量的值赋给第一个变量,再把t的值赋给第二个变量,从而实现两个数的交换。子过程编成后,交换a和b的值时,调用该过程一次,交换c和d的值时再调用该过程一次。设计步骤如下:1.编写两个数交换的子过程代码。

例:编一个交换两个整型变量值的子过程。

PrivateSubSwap(XAsInteger,YAsInteger)DimtempAsIntegerTemp=X:X=Y:Y=TempEndSub

2.编写事件过程来调用通用过程。

PrivateSubCmdchange1_Click()DimaAsInteger,bAsIntegera=4:b=5Print"交换前a,b的值为:"Print"a=";a,"b=";bCallswap(a,b)Print"交换后a,b的值为:"Print"a=";a,"b=";bEndSub

PrivateSubCmdchange2_Click()DimcAsInteger,dAsIntegerc=2:d=3Print"交换前c,d的值为:"Print"c=";c,"d=";dSwapc,dPrint"交换后c,d的值为:"Print"c=";c,"d=";dEndSub程序运行结果如下图所示:

一般格式:[Static][Public|Private]Function函数名[(参数表列)][As类型]

语句块

[函数名=表达式][ExitFunction][语句块]EndFunction6.2.1建立Function过程

函数是过程的另一种形式,当过程的执行返回一个值时,使用函数就比较简单。与子程序过程不同的是函数过程将返回一个值。6.2

Function过程说明:1.过程名即Function过程的名字。As类型指定Function过程返回值的类型,可以是Integer、Long、Single、Double、String、Currency或boolean。如果没有As子句,默认的数据类型为Variant。

2.Sub过程不能嵌套定义。3.表达式的值是函数返回的结果。在语法中通过赋值语句将值赋给函数名,该值就是Function过程返回的值。如果在Function过程中省略

“函数名=表达式”,则该过程返回一个默认值,如数值函数返回0。4.语句块是程序段,语句块中可以用一个或多个ExitFunction语句从函数中退出。5.在VB集成环境建立的方法与Sub过程完全一样。【例6.2】编写计算任意整数n的阶乘的函数过程fact。

Function过程示例

Functionfact(nAsInteger)AsLongDimpAsLong,IAsintegerp=1ForI=1tonp=p*INextIFact=pEndfunction函数返回值的类型。把求出的结果赋给函数名。【例6.3】编写一个求两个数最大公约数的函数过程。Functiongcd(mAsinteger,nAsInteger)AsIntegerDimrasAsIntegerr=mmodnDoWhiler<>0m=nn=rr=mmodnLoopGcd=nEndFunction函数返回值的类型。把求出的结果赋给函数名。分析:我们采用辗转相除法求最大公约数。

调用格式:函数名(实参列表)说明:在调用时实参和形参的数据类型、顺序、个数必须匹配。函数调用只能出现在表达式中,其功能是求得函数的返回值。6.2.2调用Function过程【例6.4】利用阶乘函数过程fact求解表达式2!+4!+6!+8!+10!的值。分析:要计算2!+4!+6!+8!+10!,首先要计算出2!、4!、6!、8!、10!。可以用函数过程fact来计算n!,每次调用求阶乘函数前给n分别赋值为2、4、6、8、10,调用5次,把每次调用的结果累加起来就能求得表达式的值。PrivateSubcmdjs_Click()DimsumAsLongDimtAsLongDimiAsIntegersum=0Fori=2To10Step2Sum=Sum+fact(i)

'调用函数过程factNextiLbloutput.Caption=sumEndSub

编写Command1事件代码。

调用fact函数语句。【例6.5】定义一个在复数范围内求平方根的函数。输入一个数,输出该数的平方根。分析:用内部函数Sqr可以得到一个数的平方根,但该数必须大于或等于0,如果是负数该函数会出现错误信息。我们定制一个自定义函数过程MySqr来解决自变量为负数的情况。PrivateFunctionmysqr(xAsDouble)AsDoubleSelectCaseSgn(x)Case1mysqr=Sqr(x)Case0mysqr=0Case-1mysqr=Sqr(Abs(x))EndSelectEndFunction

1.函数过程MYSQR。

PrivateSubCmdjs_Click()DimxAsDouble,msgAsStringx=Val(Txtx.Text)msg=x&"的平方根是:"Ifx>=0Thenmsg=msg&mysqr(x)Elsemsg=msg&mysqr(x)&"i"EndIfMsgBoxmsgEndSub2.编写事件过程来调用通用过程。

6.3过程中参数的传递

形式参数是指在定义通用过程时,出现在Sub或Function语句中的变量名,是接收数据的变量。形参的两种形式:(1)后面跟有左右圆括号的数组名。(2)除定长字符串之外的合法变量名。

6.3.1形参和实参VisualBasic中不同模块(过程)之间数据的传递有两种方式:

通过过程调用实参与形参的结合实现;使用全局变量来实现各过程中共享数据。1.形式参数

实际参数是指在调用Sub或Function过程时,传送给Sub或Function过程的常量、变量、表达式或数组名。其作用是将它们的数据(数值或地址)传送给Sub或Function过程与其对应的形参变量。2.实际参数实参表和行参表中对应的变量名不必相同,但变量的个数必须相等,而且各实际参数的书写顺序必须与相应形式参数的类型相同。例如:传值参数的两种形式:(1)定义过程时选用ByVal关键字,就是按值传递。(2)实际参数是常量或表达式。(3)定义过程时选用ByRef关键字,调用时变量用小括号括起来。传值参数的特点:形参得到的是实参的值,形参值的改变不会影响实参的值。6.3.2传值参数和传址参数1.传值参数【例6.6】运行一个程序,理解按值传递参数的含义。PrivateSubForm_Click()DimaAsInteger,bAsInteger,cAsIntegera=5:b=3:c=9ClsPrintPrint"主程序调用前的变量值a,b,c:";a;b;cCallproc(a,b,c)′实参量不变PrintPrint"主程序调用后的变量值a,b,c:";a;b;cEndSubSubproc(ByValaAsInteger,ByValbAsInteger,_ByValcAsInteger)PrintPrint"子程序中运算前的变量值a,b,c:";a;b;ca=6:b=8:c=a*bPrintPrint"子程序中运算后的变量值a,b,c:";a;b;cEndSub【例6.7】在例6.3求两个数最大公约数的基础上,使用传值调用Function过程,求两个整数的最大公约数和最小公倍数。

1.设计用户界面如下:

传值参数示例

PrivateSubCmdjs_Click()DimtempAsStringDimmAsInteger,nAsIntegerm=Val(InputBox("请输入第一个整数:"))n=Val(InputBox("请输入第二个整数:"))Ifn*m=0ThenExitSubLblgys.Caption=m&","&n&"的最大公约数是:"&Str(gcd((m),(n)))Lblgbs.Caption=m&","&n&"的最小公倍数是:"&_Str(m*n/gcd((m),(n)))EndSub2.编写事件代码。

m、n如果不用括号括起来,结果会是什么呢?

系统默认按地址传递参数,或者定义过程时选用ByRef关键字。传址参数就是让过程根据变量的内存地址去访问实际变量的内容,即形式参数和实际参数使用相同的内存地址单元,这样通过子过程可以改变变量本身的值。传址参数对应的实参必须也是变量,否则无法达到传址。常量和表达式无法传址。2.传址参数【例6.8】运行一个程序,理解按址传递参数的含义。PrivateSubForm_Click()DimaAsInteger,bAsInteger,cAsIntegera=5:b=3:c=9ClsPrintPrint"主程序调用前的变量值a,b,c:";a;b;cCallproc(a,b,c)'实参量发生变化PrintPrint"主程序调用后的变量值a,b,c:";a;b;cEndSubSubproc(aAsInteger,bAsInteger,cAsInteger)

'按地址传递PrintPrint"子程序中运算前的变量值a,b,c:";a;b;ca=6:b=8:c=a*bPrintPrint"子程序中运算后的变量值a,b,c:";a;b;cEndSub

在使用通用过程时,可以将数组或数组元素作为参数进行传递。在传送数组时,除遵守参数传送的一般规则外,还应注意以下两点:

传递整个数组时,应将数组名分别放入实参表和形参表中,并略去数组的上下界,但括号不能省。如:

Calltest(arr())如果不需要把整个数组传送给过程,而是传递数组中的某一元素,则需要在数组名后面的括号中写上指定元素的下标。如:Calltest(arr(1))6.3.3数组参数的传递【例6.9】编写ArrayReverse子程序将数组反向。PrivateSubarrayreverse(a()AsInteger)DimiAsInteger,lAsInteger,uAsInteger,_tempAsInteger

l=LBound(a)′給出数组的最小下标值

u=UBound(a)′給出数组的最大下标值

Fori=1To(u-l+1)\2temp=a(i)a(i)=a(u-i+1)a(u-i+1)=tempNextiEndSub

编写数组反向通用过程代码如下:从数组头尾开始把对应的元素互换。

调用数组反向事件过程代码如下:PrivateSubForm_click()Dimarr1(1To10)AsIntegerDimiAsIntegerFori=1To10'給数组赋值

arr1(i)=iNextiPrint"显示原数组:"Fori=1To10Printarr1(i);Nextiarrayreversearr1()'调用数组反向函数

PrintPrintPrint"显示逆序数组:"Fori=1To10Printarr1(i);

NextiEndSub1.可变参数

在前面的例子中,一个过程中的形参是固定的,调用时提供的实参也是固定的。但在VisualBasic中,可以指定一个或多个参数作为可选参数。6.3.4可选参数和可变参数

为了定义带可选参数的过程,必须在参数表中使用Optional关键字,并在过程体中通过IsMissing函数测试调用时是否传送可选参数。IsMissing函数有一个参数,它是由Optional指定的形参的名字,其返回值为Boolean类型,在调用过程时,如果没有向这个可选参数传送实参,则IsMissing函数的返回值为True,否则返回False。【例6.10】定义一个可选参数过程,用可选参数实现对两个数或三个数求和。分析:因为参数个数不定,可以用可选参数解决这个问题。其过程代码如下:

SubAdd(FirAsInteger,SecAsInteger,OptionalThird) n=Fir+Sec IfNotIsMissing(Third)Then n=n+Third EndIf Printn EndSub可选参数实例2.可变参数

如果参数个数为任意个,可使用可变参数来实现。6.3.4可选参数和可变参数

一般格式为:

Sub过程名(ParamArray数组名)

说明:这里的“数组名”是一个形参。只有名字和括号,没有上下界。由于省略了变量类型,“数组”的类型默认为变体类型。【例6.11】定义一个可变参数过程,用这个过程可以求任意多个数的和。分析:定义一个可变参数过程,用于求任意个数的和。

SubAdd(ParamArrayNumbers()) Sum=0 ForEachxInNumbers Sum=Sum+x Nextx PrintSum EndSub可变参数实例

在VisualBasic中,过程的形式参数不仅可以是变量,还可以是对象,即窗体或控件。在定义过程的形参时,如果用“AsForm”声明,则表示该形参是一个窗体。如果用“AsControl”声明,则表示该形参是一个控件。6.3.5对象参数【例6.12】设计一个包含三个窗体的程序,这些窗体按照窗体号依次循环显示,直到关闭窗体为止。分析:三个窗体在大小、位置上都相同,因此可以设计一个子过程,用以初始化各窗体的属性,包括Left、Top、Width和Height。这个子过程的代码是:SubFormSet(FormNumAsForm)FormNum.Left=2000FormNum.Top=3000FormNum.Width=5000FormNum.Height=3000EndSub对Form1编写如下的事件过程:

PrivateSubForm_Load() FormSetForm1 FormSetForm2 FormSetForm3EndSub

对3个窗体分别编写如下的事件过程:

PrivateSubForm_Click() Form1.Hide′隐藏窗体Form1 Form2.Show′显示窗体Form2 EndSub PrivateSubForm_Click() Form2.Hide′隐藏窗体Form2 Form3.Show′显示窗体Form3 EndSub PrivateSubForm_Click() Form3.Hide′隐藏窗体Form3 Form1.Show′显示窗体Form1 EndSub

6.4过程和变量的作用域

VB应用程序的结构为:

通用过程可以出现在窗体模块、标准模块中。在每个模块和过程中都可以定义和使用变量,每个过程和变量都有自己的适用范围。

过程可被访问的范围称为过程的作用域。它随所定义语句的不同而不同。按过程的作用范围来划分,过程可分为:模块级过程和全局级过程。

模块级过程:在某个窗体或标准模块中定义的过程前加上Private关键字,则该过程只能被包含过程的窗体或标准模块中的过程调用。

全局级:在某个窗体或标准模块中定义的过程前加上Pulbic关键字或缺省,则该过程为全局级过程,可以被应用程序的所有窗体或标准模块中的过程调用。

6.4.1过程的作用域

其调用方式根据过程所处的位置有如下两种:

1)在窗体中定义的过程,当外部过程要调用时,应在被调用的过程名前加上所处的窗体名。

2)在标准模块中定义的过程,如果过程名唯一,则任何外部过程都可以直接调用,否则应在被调用的过程名前加上所处的标准模块名。1.局部变量(动态变量)在一个过程内部使用Dim或Static关键字声明的变量。局部变量是只能在一个函数或过程中访问的变量,其他过程或函数不能访问此变量的数据。2.窗体/模块级变量窗体/模块级变量是指在一个窗体/模块的任何过程之外,即在“通用声明”段中用Dim或Private语句声明的变量。其作用域是整个窗体和模块。6.4.2变量的作用域3.全局变量全局变量是指在一个窗体/模块的任何过程之外声明的变量,即在“通用声明”段中用Public语句声明的变量。它的作用范围是整个应用程序。调用窗体模块定义的全局变量,应加上窗体名,在标准模块中定义的全局,如果名字唯一,则直接调用。【例6.13】在以下程序定义三种级别的同名变量x,单击命令按钮分析程序运行的结果。

本应用程序由一个标准模块和一个窗体模块组成,界面设计如图所示。

变量的作用域示例

标准模块代码如下:OptionExplicitPublicxAsInteger窗体模块代码如下:OptionExplicitPrivatexAsIntegerPrivateSubCommand1_Click()DimxAsIntegerx=x+1Text1.Text=xModule1.x=Module1.x+3Text3.Text=Module1.xEndSub

程序代码如下:PrivateSubCommand2_Click()x=x+1Text2.Text=xModule1.x=Module1.x+5Text3.Text=Module1.xEndSub

除作用域外,变量还有存活期,在这一期间变量能够保持它们的值。局部变量只在过程运行时有效,过程结束变量所占据的内存也被释放。静态变量在过程结束后仍保留变量的值,即其占用的内存单元未释放。静态变量的定义:

Static<变量名>[As<类型>]

或StaticSub/Function<过程名>([<参数列表>])6.4.3静态变量【例6.14】下面程序,用变量n记录单击窗体的次数。PrivateSubForm_Click()StaticnAsIntegern=n+1Print"已单击的次数:";n&"次"EndSub

6.5过程的嵌套与递归调用

VB在定义过程时,不能嵌套定义过程,但可以嵌套地调用过程,即被主程序调用的过程还可以调用另外的过程,这种程序结构称为过程的嵌套。例如:6.5.1过程的嵌套

在一个过程(Sub过程或Function过程)中调用另外一个过程,这称为过程的嵌套调用,而过程直接或间接地调用自身,则称为过程的递归调用。【例6.15】输入参数n和m,求组合数的值。

过程嵌套示例

分析:把求阶乘与求组合数公式分别定义为Function过程。求组合数用一个过程Comb来实现,而求n!的工作则由过程Fact来实现。在Comb过程中需要多次调用Fact过程,这就是过程的嵌套调用。PrivateFunctionFact(x)AsLongDimpAsLong,iAsIntegerp=1Fori=1Toxp=p*iNextFact=pEndFunctionPrivateFunctionComb(n,m)Comb=Fact(n)/(Fact(m)*Fact(n-m))EndFunctionPrivateSubCmdjs_Click()DimmAsInteger,nAsIntegerm=Val(Txtm.Text)n=Val(Txtn.Text)Ifm>nThenMsgBox"参数输入时必须符合n≥m!"ExitSubEndIfLblouput.Caption=Comb(n,m)EndSub过程中又调用其它过程

过程的递归调用是指一个过程直接或间接地调用自身。当一个问题可以基于更小规模的同类问题求解,而最小规模的问题可以直接求解,则这个问题可以用过程的递归调用解决。例如,阶乘、级数运算、幂指数运算都是可以借助过程的递归调用求解。6.5.2过程的递归【例6.16】利用递归调用,计算n!。

分析:0的阶乘规定为1,正整数都有其阶乘,定义为n×(n-1)×(n-2)×…×2×1。因此,正整数n的阶乘可用下式定义。PrivateSubCommand1_Click()DimnAsIntegern=Val(Txtn.Text)Ifn>0Andn<=20ThenLbloutput.Caption=n&"的阶乘为"&fact(n)ElseMsgBox"数据输入超出范围!"Txtn=""Txtn.SetFocusExitSubEndIfEndSubStaticFunctionfact(nAsInteger)AsDouble

'Function过程fact的程序代码

Ifn>0Thenfact=n*fact(n-1)Elsefact=1EndIfEndFunction6.6常用算法举例

【例6.17】判断一个数是否是回文数。分析:所谓回文数是指顺读和倒读这个数都相同。我们把输入的正整数看成一个数字串,从两头到中间逐一比较,如果都相同就是回文数,有一个不相同就不是。判断一个数是否是回文数的子过程代码:PublicSubhw(ByValnAsLong,flagAsBoolean)DimsAsString,iAsIntegerflag=True'flag为回文数标志,为真是回文数,为假不是

s=Trim(Str(n))Fori=1ToInt(Len(s)/2)IfMid(s,i,1)<>Mid(s,Len(s)-i+1,1)Thenflag=FalseExitForEndIfNextiEnd命令按钮Cmdpd的单击事件代码:PrivateSubcmdpd_Click()DimxAsLong,ishwAsBooleanx=Val(Txtx.Text)Callhw(x,ishw)IfishwThenlbloutput.Caption=x&"是回文数"Elselbloutput.Caption=x&"不是回文数"EndIfEndSub命令按钮Cmdclear的单击事件代码:PrivateSubCmdclear_Click()Txtx=""lbloutput=""Txtx.SetFocusEndSub【例6.18】显示100以内的所有素数,并计算这些素数的和。分析:素数是指只能被1和它本身整除的数。我们可以编写一个函数过程Isprime判断一个数是否是素数,然后对100以内的数反复调用Isprime函数来判断该数是否为素数,如果是则显示出来,并把这些素数累加起来,最后输出它们的和。判断一个数是否是素数的函数过程代码:PublicFunctionisprime(xAsInteger)AsBooleanDimflagAsBooleanDimiAsIntegerflag=True'flag为标志变量,为真是素数,为假不是

Fori=2Tox-1IfxModi=0Thenflag=FalseExitForEndIfNextiisprime=flagEndFunction命令按钮Cmddisp的单击事件代码:PrivateSubCmddisp_Click()DimiAsInteger,sAsInteger,nAsIntegers=0:n=0's用来表示素数的和,n用来记录素数的个数

Fori=2To99Ifisprime(i)Thenn=n+1Picdisp.Printi;

'每行输出10个素数

IfnMod10=0ThenPicdisp.Prints=s+iEndIfNextiPicdisp.PrintPicdisp.PrintPicdisp.PrintTab(8);"100以内素数的和为:";sEndSub【例6.19】生成10个100以内互不相等的随机整数,并求出其中的最小值。分析:编写一个函数过程产生10个互不相等的随机整数并存入数组,再编写一个函数过程求数组中的最小值,即可把这一问题解决。

考虑到要在不同的过程中使用数组,所以首先在模块的通用段声明数组:Dima(1To10)AsInteger产生一个随机数组并将数组中10个数组元素连成一个字符串的函数过程代码:PublicFunctionSjs(p()AsInteger)AsStringDimTemp

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论