
VB程序设计第8章-设计和使用子过程.ppt
41页VBVB程序设计第程序设计第8 8章章- -设计和设计和使用子过程使用子过程学习目标:(1)掌握定义、调用子过程和函数的方法2)理解参数传递中传值和传址的不同含义了解数组参数的传递3)知道过程与变量的作用域4)了解键盘和鼠标的各种事件5)能够灵活运用本章所学知识进行程序设计第8章 设计和使用子过程第八章过程过程是用来执行一个特定任务的一段程序代码VB中有两类过程:(1)由系统提供的内部函数过程和事件过程事件过程是构成VB应用程序的主体在前面的学习中,我们已经接触到很多事件过程,如窗体和按钮的Click事件过程,文本框的Change事件过程等2)用户根据自己的需要定义、供事件过程多次调用的自定义过程在程序设计过程中,可以将一些常用的功能编写成自定义过程,供多个不同的事件过程多次调用;从而减少重复编写代码的工作量,实现代码重用,使程序简练、便于调试和维护自定义过程又分为以下几类:以“Sub”保留字开始的子过程以“Function”保留字开始的函数过程以“Property”保留字开始的属性过程以“Event”保留字开始的事件过程本章主要介绍比较常用的子过程和函数过程8.1 过程概述第八章过程子过程是用特定格式组织起来的一组代码,通常用来完成一个特定的功能,可以被其它过程作为一个整体来调用。
8.2 子过程的定义与调用第八章过程在形式上,子过程与事件过程相类似,但又有所区别:事件过程的过程名由对象名和事件名连接而成子过程的过程名可以是一个任意合法的标识符子过程的形式如下:[Static][Public|Private]Sub 子过程名[(形参列表)] [局部变量或常数定义] [语句序列] [Exit Sub] [语句序列]End Sub8.2 8.2 子过程的定义与调用8.2.1 子过程的形式形式说明:(1)“子过程名”要遵守标识符的命名规则2)[(形参列表)] 类似于变量声明,是用“,”分隔开的若干个变量,格式如下:变量名1 [As 类型] ,变量名2 [As 类型],……或:变量名1 [类型符] ,变量名2 [类型符],……(3)[语句序列] 是VB的程序段,在此编写语句,实现相应功能4)[Exit Sub] 表示中途退出子过程5)[Static][Public|Private] 的意义在8.5节中介绍实例说明:Sub sum(x%, y%, s%) s = x + yEnd Sub上面子过程的名称为sum,其有三个整型的形参x、y、s,语句序列为“s = x + y”,调用该过程可以实现求两数之和。
[(形参列表)]为可选项,即此项可有可无没有参数的过程称为无参过程例如:Sub printhello Print "hello"End Sub上面的过程不带参数,当调用该过程时,打印输出“hello”第八章过程定义子过程有两种方法:(1)利用代码窗口直接定义在代码窗口把插入点放在所有过程之外,按照子过程的形式,直接输入即可2)使用“添加过程”对话框进行定义8.2 子过程8.2.2 定义子过程第八章过程步骤如下:(1)切换到代码窗口2)选择“工具”菜单下的“添加过程”命令,弹出“添加过程”对话框,见图8-13)在“名称”框中输入过程名例如图8-1中显示输入的过程名为“sum”4)在“类型”组中选取“子程序”5)在“范围”组中选取“公有的”定义一个公共级的全局过程,或选取“私有的”定义一个局部过程8.2 子过程8.2.2 定义子过程(6)单击“确定”按钮,完成对子过程的定义此时,代码窗口中会自动出现子过程的代码框架例如单击图8-1所示对话框的“确定”按钮后,在代码窗口中会出现以下代码:Public Sub sum()End Sub可以在子过程的代码框架中输入语句,以完成相应功能。
第八章过程8.2.3 子过程的调用要执行一个子过程,必须先调用该子过程每次调用子过程都会执行Sub和End Sub之间的语句子过程以Sub开始,以End Sub结束当程序遇到End Sub时,将退出子过程,并返回到调用语句之后的语句继续执行子过程的调用有两种方式:(1)使用Call语句:格式:Call 过程名[(实参列表)]举例:Call sum(a, b, c)8.2 子过程8.2.3 子过程的调用(2)直接使用过程名:格式:过程名[实参列表]举例:sum a, b, c调用方式的说明:(1)“实参列表”中的实参必须与形参保持个数相同,位置与类型一一对应2)实参可以是常量、变量、表达式3)参数与过程名之间用空格隔开,参数与参数之间用逗号分隔4)调用子过程时,会把实参的值传递给形参,称为参数传递,有传址和传值两种方式默认为传址方式,此时实参和形参共用一个内存单元,对形参的操作等同于对实参操作传值时实参和形参使用不同内存单元,对形参的操作不会对实参产生影响8.4节中有详述5)若直接使用过程名调用过程,则过程名后不能加括号,参数直接跟在过程名之后6)用Call 语句调用过程时,过程名后必须加括号,参数放在括号之内。
第八章过程【例8.1】编写求矩形面积的子过程,通过调用此子过程来求窗体上不同按钮的面积编写:新建工程,建立二个大小不同的按钮,依次双击这二个按钮,输入代码如下Sub SArea(sw!, sh!)'求矩形面积的子过程,被事件过程调用时执行 Dim area! area = sw * sh '形参通过实参获得某按钮的宽和高,用来计算面积 Print "面积为:"; areaEnd Sub '退出子过程,并返回到调用语句之后的语句继续执行8.2 子过程8.2.4 应用举例Private Sub Command1_Click() '事件过程,当按钮Command1被单击时执行 Dim w!, h! w = Command1.Width'按钮宽度可由Width属性获得,单位为Twip h = Command1.Height'按钮高度可由Height属性获得,单位为Twip Print Command1.Caption; SArea w, h'调用子过程SArea,实参把宽和高传递给形参End SubPrivate Sub Command2_Click() 事件过程,当按钮Command1被单击时执行 Dim w!, h! w = Command2.Width'将要作为实参的w通过Width属性获得宽度 h = Command2.Height'将要作为实参的h通过Height属性获得高度 Print Command2.Caption; SArea w, h'调用时实参w、h把宽和高传递给形参sw、shEnd Sub运行程序,分别单击大小不同的两个按钮,窗体显示相应按钮的面积,如图8-2所示。
第八章过程【例8.2】编写求N!的子过程,通过调用此子过程来计算5 ! + 8 ! – 6 ! 编写:新建工程,双击窗体,在Form的事件列表中选择Click项,输入代码如下Sub JCh(N%, p&)'求N!的子过程,被事件过程调用时执行 Dim i% p = 1 For i = 1 To N'用循环求出N!,形参N的值由调用语句中的相应实参获得 p = p * i Next i'循环结束后p = N!End Sub'由于默认为传址,形参与实参共址,即相应实参与p的值一样均为N!Private Sub Form_Click() Dim a&, b&, c&, d& Call JCh(5, a)'调用子过程JCh,此时会跳转到子过程处执行语句 Call JCh(8, b)'子过程执行完后,返回此语句,执行后再次跳转到子过程 Call JCh(6, c))'同上 d = a + b - c'三次调用子过程,使与形参p相对应的实参值为5!,8!,6! Print "5!+8!-6!="; dEnd Sub8.2 子过程8.2.4 应用举例输入完成后,运行程序。
单击窗体,会显示5 ! + 8 ! – 6 ! 的计算结果,如图8-3所示第八章过程函数过程与子过程最主要的区别在于:函数过程有返回值,而子过程没有返回值函数过程是自定义过程的另一种形式当过程的执行需要返回一个值时,使用函数过程比用子过程更加简单方便VB提供了许多内部函数,如Sin( ),Sqr( )等,在编写程序时,只需写出函数名和相应的参数,就可得到函数值在编程时,可以像调用内部函数一样来使用函数过程,不同之处在于函数过程所实现的功能是我们自己编写的8.3 函数过程第八章过程函数的形式如下:[Static][Public|Private] Function 函数名([形参列表]) [As类型] [局部变量或常数定义] [语句序列] [Exit Function] [语句序列] 函数名=表达式End Function 形式说明:(1)As类型:指明函数过程返回值的类型2)在函数过程中至少对函数名赋值一次从函数过程返回时函数名的值就是返回值3)无论函数有无参数,函数名后的括号都不能省略4)[Exit Function]表示中途退出函数过程。
8.3 函数过程8.3.1 函数的形式实例说明:Function sum(x%, y%) As Integer sum = x + yEnd FunctionPrivate Sub Form_Click() ' d = sum(2, 3) Print dEnd Sub在上述函数过程中,“As Integer ”定义名为sum的函数过程返回值为整型,通过语句“sum = x + y”对函数名赋值执行上述语句段,会在窗体上输出数字5第八章过程同子过程一样,函数过程的定义方法也有两种:(1)利用代码窗口直接定义在代码窗口把插入点放在所有过程之外,按照函数过程的形式,直接输入即可2)使用“添加过程”对话框进行定义步骤与定义子过程相同,只是第4步更改为在“类型”组中选取“函数”即可函数的调用:调用函数过程可以由函数名带回一个值给调用程序,被调用的函数必须作为表达式或表达式中的一部分,再与其他的语法成分一起配合使用因此,与子过程的调用方式不同,函数不能作为单独的语句加以调用最简单的情况就是在赋值语句中调用函数过程,其形式为: 变量名 = 函数过程名([实参列表])8.3 函数过程8.3.2 函数的定义与调用第八章过程【例8.3】修改例8.2程序,,使用函数过程实现对5 ! + 8 ! – 6 ! 的计算。
编写:新建工程,双击窗体,在Form的事件列表中选择Click项,输入代码如下Function jch2(N%) As Long'求N!的函数过程,返回值的类型为长整型 Dim i% jch2 = 1 For i = 1 To N jch2 = jch2 * i '在循环体中对函数名赋值,实现累乘求N! Next i'循环结束后jch2 = N!End Function '返回调用语句,并把函数名中的值作为函数的返回值Private Sub Form_Click() Dim d& d = jch2(5) + jch2(8) - jch2(6) ' 在表达式中三次调用函数过程,返回值分别为5!、8!、6! Print "5!+8!-6!="; dEnd Sub输入完成后,运行程序单击窗体,会显示5 ! + 8 ! – 6 ! 的计算结果,如图8-3所示8.3 函数过程第八章过程【例8.4】编写程序,要求调用函数过程求出两个自然数的最大公约数。
分析:求最大公约数可以用“辗转相除法”,其算法思想如下:(1)x除以y得到余数r;(2)若r = 0,则y为要求的最大公约数,算法结束;否则执行(3);(3)y → x,r → y,再转到(1)执行8.3 函数过程编写:新建工程,双击窗体,在Form的事件列表中选择Click项,输入代码如下Function gcd%(x%, y%)'求最大公约数的函数过程,返回值的类型为整型 Dim r% r = x Mod y'x除以y得到余数r While r <> 0'若r不等于0,不断循环 x = y y = r'y → x,r → y r = x Mod y Wend gcd = y'若r = 0,则y为要求的最大公约数,赋值给函数名End Function'返回调用语句,并把函数名中的值作为函数的返回值Private Sub Form_Click() Dim m%, n% m = InputBox("请输入第一个自然数:") n = InputBox("请输入第二个自然数:") Print m; "和"; n; "的最大公约数是:"; Print gcd(m, n)'调用函数过程,执行完后返回最大公约数,用Print 输出End Sub运行程序,单击窗体,在弹出的输入框中分别输入6和9,结果如图8-4所示。
第八章过程在上述实例调用过程时,往往需要通过参数传递数据参数传递的方式有两种:传址和传值在通过传址方式进行参数传递时,数组也可以作为过程的参数8.4 参数传递第八章过程(1)传址在调用一个过程时,如果是用传址方式进行参数传递,则会将实参的内存地址传递给形参,即让形参和实参使用相同的内存单元因此,在被调用的过程中对形参的任何操作都变成了对相应实参的操作,实参的值就会随形参的改变而改变传址是默认的参数传递方式,本章前面的实例均为传址当参数是数组时,或要将子过程中的结果返回给主调程序时,只能用传址方式当参数是字符串或数组时,使用传址传递直接将实参的地址传递给过程,会使程序的效率提高8.4 参数传递8.4.1 传址与传值(2)传值按传值方式传递参数时,系统将实参的值复制给形参,形参与实参使用不同的内存单元因此,被调过程对形参的操作是在形参自己的存储单元中进行的,实参的值不会随形参的改变而改变当过程调用结束时,这些形参所占用的存储单元也同时被释放因此在过程中对形参的任何操作都不会影响到实参传值不是默认的参数传递方式要使用传值方式时,必须在形参前加“ByVal”关键字使用传值方式,可以减少过程间的关联;从而增加了程序的可靠性,减少了程序的调试难度。
3)传址与传值的区别最主要的区别是:对形参的操作是否会对实参产生影响传址时,实参和形参共用一个内存单元,对形参的操作等同于对实参操作传值时,实参和形参使用不同内存单元,对形参的操作不会对实参产生影响形式上的区别是:在形参前是否有关键字“ByVal”使用传址时,无需在形参前加任何关键字使用传值时,需要在形参前加关键字“ByVal”第八章过程(4)应用举例【例8.5】修改例8.4程序,利用求出的最大公约数计算两数的最小公倍数在调用函数过程时,要求分别用传址和传值的参数传递方式,从显示结果中判断哪种方式适用于本例1)分析:将原两数相乘除以最大公约数,即可求出最小公倍数编写两个求最大公约数的函数过程,分别采用传址和传值的方式通过两个单选钮来选择使用那种方式2)界面设计:新建工程,在窗体上建立两个单选钮,分别设置单选钮的Caption属性为“传址”和“传值”,并将“传址”单选钮的Value属性设为True8.4 参数传递(3)编写代码:双击窗体,输入代码如下Function gcd%(x%, y%)'使用传址时,无需在形参前加任何关键字 Dim r%'本例中,形参x、y与实参m、n共用一个内存单元 r = x Mod y While r <> 0 x = y '本例中,对形参x、y的操作等同于对相应实参m、n的操作 y = r '实参m、n的值就会随形参x、y的改变而改变 r = x Mod y Wend gcd = yEnd FunctionFunction gcd2%(ByVal x%, ByVal y%) '传值时,需在形参前加关键字ByVal Dim r% '形参x、y与实参m、n用不同内存单元 r = x Mod y While r <> 0 x = y'本例中,对形参x、y的操作不会对实参m、n产生影响 y = r'实参m、n的值就不会随形参x、y的改变而改变 r = x Mod y Wend gcd2 = yEnd FunctionPrivate Sub Form_Click() Dim m%, n%, a%, b% m = InputBox("输入第一个自然数:", , 6) n = InputBox("输入第二个自然数:", , 9) Print " 您输入数字为:"; m; "和"; n If Option1.Value Then a = gcd(m, n)'“传址”单选钮处于选中状态,则调用函数过程gcd Else a = gcd2(m, n)'“传值”单选钮处于选中状态,则调用函数过程gcd2 End If b = m * n / a'求最小公倍数 Print m; "和"; n; "的最大公约数是:"; a Print m; "和"; n; "的最小公倍数是:"; bEnd Sub输入完成后,运行程序。
点选“传址”单选钮,单击窗体,在输入框中分别输入6和9,结果如图8-5(a)所示点选“传值”单选钮,单击窗体,在输入框中分别输入6和9,结果如图8-5(b)所示显而易见,传值方式适用于本例a)使用传址方式 (a)使用传值方式 第八章过程【例8.6】分别使用传址和传值的传递方式编写“实现两数交换”的子过程,要求分别显示在这两种方式下实参与形参的前后变化1)界面设计:新建工程,在窗体上建立两个单选钮,分别设置单选钮的Caption属性为“传址”和“传值”,并将“传址”单选钮的Value属性设为True2)编写代码:双击窗体,输入代码如下Sub swap(x%, y%)'传址 Dim t% Print "交换前:"; " x ="; x; " y ="; y t = x: x = y: y = t Print "交换后:"; " x ="; x; " y ="; yEnd Sub8.4 参数传递Sub swap2(ByVal x%, ByVal y%)'传值 Dim t% Print "交换前:"; " x ="; x; " y ="; y t = x: x = y: y = t Print "交换后:"; " x ="; x; " y ="; yEnd SubPrivate Sub Form_Click() Dim a%, b% a = 5: b = 8 Print "调用前:"; " a ="; a; " b ="; b If Option1.Value Then swap a, b Else swap2 a, b End If Print "调用后:"; " a ="; a; " b ="; bEnd Sub运行程序,分别在“传址”和“传值”单选钮处于选中状态时单击窗体,如图8-6所示。
a)使用传址方式 (a)使用传值方式 第八章过程8.4 参数传递在使用传址方式进行参数传递时,数组也可以作为过程的参数因此,当用数组作为过程的参数时,进行的不是“值”的传递,而是“址”的传递即将数组的起始地址传给被调过程的形参数组,使得被调过程在执行中,实参数组与形参数组共享一组存储单元此时对形参数组操作,就等同于对实参数组操作,所以被调过程中对形参数组的任何改变都将带回给实参数组在定义过程时,形参列表中的数组参数用数组名后跟一对空的圆括号表示在调用过程时,实参列表中的数组参数可以只用数组名表示,省略圆括号如果被调过程不知道实参数组的上下界,可在被调过程中用LBound和 Ubound求得8.4.2 数组参数的传递第八章过程8.4 参数传递【例8.7】用随机数产生一个一维数组,用此数组作参数,求数组中所有偶数元素之和编写:新建工程,双击窗体,输入代码如下 Function sum%(b%())'形参中的数组参数用数组名后跟一对空的圆括号表示 Dim i% For i = LBound(b) To UBound(b)'用LBound和 Ubound求得上下界 If b(i) Mod 2 = 0 Then sum = sum + b(i) End If Next iEnd FunctionPrivate Sub Form_Click() Dim a%(10), s%, i% For i = 1 To 5'用循环和Rnd函数产一个一维数组 a(i) = Int(Rnd * 100) Print a(i); Next i Print s = sum(a()) Print " 数组中偶数元素之和为:"; sEnd Sub行程序,单击窗体,输出一维数组中的所有元素以及偶数元素之和,如图8-7所示。
第八章过程8.5 过程与变量的作用域8.5.1 代码模块的概念VB中可以存储代码的模块有三种:窗体模块、标准模块和类模块在窗体模块、标准模块和类模块这三种模块中,都可以包含声明(常量、变量声明)和过程(子过程、函数过程)他们形成了工程的一种模块层次结构,可以较好的组织工程,同时也便于代码的维护三种模块在工程资源管理器中的状态如图8-9所示1)窗体模块:窗体模块保存在扩展名为 .frm的文件中每个窗体对应一个窗体模块窗体模块包含窗体变量的说明、窗体及窗体上控件的属性设置、事件过程、窗体内的通用过程、外部过程的窗体级声明2)标准模块:标准模块保存在扩展名为 .bas的文件中在多窗体程序中,可以在标准模块中编写子过程和函数过程,以便多个不同的窗体调用标准模块包含公有或模块级的变量、常量、类型、外部过程和全局过程的全局声明或模块级声明3)类模块:类模块保存在扩展名为 .cls的文件中可以在.类模块中编写代码建立新对象,这些新对象可以包含自定义的属性和方法,可以在应用程序内的过程中使用类模块与标准模块的不同之外在于标准模块仅仅含有代码,而类模块即含有代码又含有数据类模块可以视为没有物理表示的对象。
第八章过程8.5 过程与变量的作用域8.5.2 过程的作用域这里只讨论窗体模块和标准模块内过程的作用域过程的作用域是指过程在VB应用程序(工程)中能被识别的范围过程的作用域分为模块级(或称文件级)和全局级(或称工程级)1)模块级:指在某个窗体模块或标准模块内用Private定义的子过程或函数过程,这些过程只能被本窗体模块或本标准模块中的过程调用其作用域为本模块2)全局级:指在窗体模块或标准模块中定义的过程,其默认是全局的,也可加Public进行说明其作用域为本应用程序全局级过程可供该应用程序内的所有窗体模块和标准模块中的过程调用,但根据过程所处的位置不同,其调用方式有所区别:在窗体定义的过程,外部过程要调用时,必须在过程名前加定义该过程的窗体名在标准模块定义的过程,外部过程均可调用,但必须保证该过程名是唯一的,否则要加定义该过程的标准模块名过程作用域的相关规则见表8-1 能,但过程名必须唯一,否则要加标准模块名例:Call 标准模块名.Sub2能,但必须在过程名前加窗体名例:Call 窗体名.Sub2不能不能能否被本应用程序其他模块调用能能能能能否被本模块其他过程调用过程名前加Public或缺省例:[Public] Sub Sub2过程名前加Private例:Private Sub Sub1定义方式标准模块窗体模块标准模块窗体模块全局级模块级作用范围第八章过程8.5 过程与变量的作用域8.5.3 变量的作用域变量的作用域是指变量能被某一过程识别的范围。
变量的作用域决定了哪些过程可访问该变量变量的作用域分为局部级(过程级)、模块级和全局级按照作用域的大小,变量可分为:局部变量、模块级变量和全局变量1)局部变量:指在过程内用Dim语句声明的变量(或不加声明直接使用的变量),只能在本过程中使用,别的过程不可访问当该过程被调用时,系统给局部变量分配存储单元并进行变量的初始化,执行该过程时对局部变量可进行存取操作但是,一旦该过程体执行结束,则局部变量的内容就会自动消失,所占用的存储单元也被释放2)模块级变量:指在一个窗体模块或标准模块的任何过程外,即在“通用声明”段中用Dim语句或用Private语句声明的变量,可被本模块的任何过程访问3)全局变量:指在窗体模块或标准模块的任何过程之外,即在“通用声明”段中用Public语句声明的变量,可被应用程序的任何过程或函数访问全局变量的值在整个应用程序中始终不会消失和重新初始化,只有当整个应用程序执行结束时,才会消失变量作用域的相关规则见表8-2能能,但在变量名前加窗体名不能不能被其他模块存取能能不能被本模块的其他过程存取模块的“通用声明”段模块的“通用声明”段在过程中声明位置PublicDim、PrivateDim、Static声明方式标准模块窗体模块全局变量模块级变量局部变量作用范围第八章过程8.5 过程与变量的作用域【例8.8】编写程序,演示不同作用域变量的使用。
1)分析:可以使用求三数之和的实例进行演示定义三个不同作用域的数值型变量,并赋于数值;在主窗体中引用三个变量进行求和,并显示三个变量的值和计算结果编写:新建工程,双击窗体,输入代码如下:Private b%'模块级变量Private Sub Form_Click() Dim a%, s%'局部变量 a = 5 s = a + b + Form2.c'引用各级变量 Print " 局部变量: a ="; a Print " 模块级变量:b ="; b Print " 全局变量:Form2.c ="; Form2.c Print " a + b + Form2.c ="; sEnd SubPrivate Sub Form_Load() b = 8'给模块级变量赋值 Form2.ShowEnd Sub添加Form2窗体,双击此窗体,输入代码如下:Public c'定义全局变量Private Sub Form_Load() c = 6'给全局变量赋值End Sub运行程序,单击Form1窗体,结果如图8-10所示 上例中,在Form1窗体的Click事件过程中引用了Form2窗体中定义的全局级变量c。
由此可以看出,在代码窗口“通用声明”段中用Public定义的变量确实是在整个应用程序中起作用的在实际编程时,还可能出现不同级声明相同的变量名的情况一般来说,在同一模块中定义了不同级但有相同名的变量时,系统优先访问作用域小的变量名如执行下列程序段:Public a As Integer'全局变量Private Sub Form_Click() Dim a As Integer'局部变量 a = 10'给局部变量赋值 Form1.a = 20'给全局变量赋值时,必须加窗体名 Print a; Form1.a'输出局部变量和全局变量的值End Sub执行完成后,会在窗体上显示“10 20”上述程序段定义了全局变量和局部变量都为a,在定义局部变量的过程Form_Click内访问a,则局部变量优先级更高,会把全局变量“屏蔽”掉;要访问全局变量时,则必须在全局变量名a前加模块名第八章过程8.5 过程与变量的作用域由表8-2可知,局部变量除了用Dim语句声明外,还可用Static语句将变量声明为静态变量静态变量在程序运行过程中可保留变量的值也就是说,每次调用过程后,用Static说明的变量会保留运行后的结果;而在过程内用Dim说明的变量,每次调用过程结束,都会将这些局部变量释放掉。
形式如下:Static 变量名 [As类型]Static Function 函数名([形参列表])[As 类型]Static Sub 过程名 [(形参列表)]8.5.4 静态变量第八章过程8.5 过程与变量的作用域【例8.9】编写程序,用来演示静态变量与过程内其他变量的不同1)分析:可以通过循环语句来多次调用一个子过程,在子过程中分别用Static和Dim语句来定义变量,并将变量进行累加和输出,以进行演示8.5.4 静态变量(2)编写:新建工程,双击窗体,输入代码如下:Sub test() Dim x As Integer, m As String'定义动态变量 Static y As Integer, n As String'定义静态变量 x = x + 1 y = y + 1 m = m & "*" n = n & "*" Print " x ="; x; " y ="; y; " m = "; m; " n = "; nEnd SubPrivate Sub Form_Click() Dim i% For i = 1 To 5 test Next iEnd Sub行程序,单击窗体,结果如图8-11所示。
第八章过程8.5 过程与变量的作用域上例中,x、y、m、n都是过程test中的局部变量,y、n被说明为静态变量,每次调用时保持上一次的值,所以使用y、n可以实现累加;x、m是动态变量,每次调用都被重新初始化为0或空字符串,因此他们在窗体上输出的值总保持不变在过程头的起始处加上Static关键字,会使过程中的所有局部变量都成为静态变量,无论它们是用Static、Dim或Private声明的还是隐式声明的可以将Static放在任何Sub或Funtion过程头的前面,包括事件过程和声明为Private的过程例如将上列中过程首语句改为:Static Sub test()则此过程中所有的局部变量都成为静态变量;即无论是Dim声明的x、m,还是用Static声明的y、n,均为静态变量8.5.4 静态变量第八章过程8.6 鼠标事件鼠标事件是指由用户操作鼠标而引发的能被VB中各种对象所识别的事件鼠标事件是鼠标应用的基础而鼠标对于Windows应用程序设计来说几乎是必需的,尤其是在图形图像处理的程序设计中,显得更为重要所以有必要对鼠标的各种事件进行了解第八章过程8.6 鼠标事件除了单击(Click)和双击(DblClick)外,重要的鼠标事件还有下列三个:MouseDown:鼠标的任一键被按下时触发该事件。
MouseUp:鼠标的任一键被释放时触发该事件MouseMove:鼠标被移动时触发该事件第八章过程8.6 鼠标事件窗体以及工具箱中的大多数控件都能响应这三个事件所以,在程序设计时,需要注意这些事件被什么对象识别,即事件发生在什么对象上面当鼠标指针位于窗体中没有控件的区域时,窗体将识别鼠标事件当鼠标指针位于窗体上的某个控件上方时,此控件将识别鼠标事件以Form 对象为例,与上述鼠标事件相对应的是鼠标事件过程如下:Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)第八章过程8.6 鼠标事件对鼠标事件过程的说明:(1)Button:是一个三位二进制整数,表示用户按下或释放的鼠标键。
Button值与鼠标键状态的对应关系如表8-3所示二进制值十进制值VB常数值鼠标对应状态描述0011vbLeftButton按下左键0102vbRightButton按下右键0113vbLeftButton+ vbRightButton同时按下左键和右键1004vbMiddleButton按下中间按钮1015vbLeftButton+vbMiddleButton同时按下左键和中间按钮1106vbRightButton+vbMiddleButton同时按下右键和中间按钮1117vbRightButton+vbMiddleButton+vbLeftButton同时按下鼠标三按钮第八章过程8.6 鼠标事件(2)Shift:是一个三位二进制整数,表示鼠标事件发生时Shift,Ctrl和Alt键的状态二进制值与三键状态的对应关系如表8-4所示二进制值十进制值VB常数值对应状态描述0011vbShiftMask按下Shift键0102vbCtrlMask按下Ctrl键1004vbAltMask按下Alt键0113vbShiftMask +vbCtrlMask按下Shift键和Ctrl键1015vbShiftMask +vbAltMask按下Shift键和Alt键1106vbCtrlMask +vbAltMask按下Ctrl键和Alt键1117vbCtrlMask+vbAltMask+ vbShiftMask按下Ctrl键、Alt键和Shift键第八章过程8.6 鼠标事件(3)X,Y:返回的都是单精度数值,表示鼠标指针的当前位置。
该鼠标位置数值是参照接受鼠标事件的窗体的坐标系统确定的第八章过程8.6 鼠标事件【例8.10】编写程序,显示鼠标指针的当前位置1)分析:当鼠标移动时,会触发MouseMove事件在Form_MouseMove事件过程中通过参数X、Y可获得鼠标指针的当前位置2)编写:新建工程,在Form的事件列表中选择MouseMove项,输入代码如下Private Sub Form_MouseMove(Button As Integer, _Shift As Integer, X As Single, Y As Single) Form1.Caption = "X:" & X & " Y:" & YEnd Sub运行程序,将鼠标在窗体上移动,会看到标题栏显示鼠标位置,如图8-12所示第八章过程8.7 键盘事件在VB中,重要的键盘事件有下列三种:KeyPress:用户按下并且释放一个会产生ASCII码的键时触发该事件KeyUp:用户按下键盘上任意一个键时被触发KeyDown:用户释放键盘上任意一个键时被触发在引发键盘事件的同时,用户所按的键盘码作为实参传递给相应的事件过程,供程序判断识别用户的操作。
第八章过程8.7 键盘事件KeyPress事件只对会产生ACSII码的按键有反应,包括数字、大小写字母、标点、ENTER、TAB、BACKSPACE等键如果按下不会产生ACSII码的按键,如按下如方向键,则KeyPress事件不会发生而KeyDown和KeyUP则提供了最低级的键盘响应与上述键盘事件相应的键盘事件过程如下:Sub Object_KeyPress([Index As Integer,] KeyAscii As Integer)Sub Object_KeyDown([Index As Integer,] KeyCode As Integer, Shift As Integer)Sub Object_KeyUp([Index As Integer,] KeyCode As Integer, Shift As Integer)第八章过程8.7 键盘事件对键盘事件过程说明:(1)Object:代表一个对象名称2)KeyAscii:返回与按键相对应的ASCII码值3)KeyCode:返回用户操作键的扫描代码它告诉事件过程用户所操作的物理键位也就是说,只要是在同一个键上的字符,它们返回的KeyCode的值是相同的。
如对于字符“A”和“a”,它们在KeyUP或KeyDown事件中的返回值都是相同的,而在KeyPress中的返回值却是不一样的4)Shift:是一个整数,与鼠标事件过程中的Shift含义相同5)Index:是一个整数,用来惟一地标识一个在控件数组中的控件第八章过程8.7 键盘事件【例8.11】编写程序,用来演示KeyPress和KeyDown事件过程中,参数KeyAscii和KeyCode的不同1)分析:通过在键盘事件中对输入的大小写字母进行显示,可以演示二者的区别2)编写:新建工程,在Form的事件列表中分别选择KeyPress和KeyUp项,输入代码如下Private Sub Form_KeyPress(KeyAscii As Integer) If KeyAscii >= 65 And KeyAscii <= 122 Then Print " 您输入了 "; Chr(KeyAscii) '如果输入的是字母,则输出此字母 End IfEnd SubPrivate Sub Form_KeyUp(KeyCode As Integer, Shift As Integer) If KeyCode >= 65 And KeyCode <= 122 Then Print " 您按下了 "; Chr(KeyCode); " 键" End IfEnd Sub运行程序,依次输入小字母a、b和大写字母A,结果如图8-13所示。
在上例运行结果中可以看出,对于在同一个键上二个不同的字符,有以下情况:返回的KeyCode值是相同的,均是此按键下档字符的ASCII码值;返回的KeyAscii值并不相同,分别是此二字符相对应的ASCII码值第八章过程小结结束本章后,我们应该熟练的掌握了过程、函数的定义及调用方法;能够理解参数传递中传值和传址的不同含义,知道如何进行数组参数的传递;可以清楚的知道某过程或变量的作用域;了解并理解键盘和鼠标的各种事件结束!结束!。
