CSDN博客

img 9116

Flash 中的OOP(下)

发表于2004/6/7 9:39:00  898人阅读

           Flash 中的OOP(下)

四、事件处理(Event Handler

事件处理方法作为类的一个方法存在,当某个事件被触发后,事件处理方法就被调用。事件处理方法它首先是一个方法,并且它可以与对象的具体事件关联。所以它应该具备方法(Function)的一般特性,唯一不同的是事件处理方法没有返回值。事件也可以使用程序模拟调用,例如何以在onPress事件中可以调用onRelease事件,这一点与JavaScript类似。事件处理方法通常在时间轴的第一帧定义:

var P:Function=new Function(); //声明和定义一个方法

P=function() //给方法变量赋值

{

       trace("Press") ;

}

this.onPress=P;  //把方法与事件关联,this指代当前时间轴

由于这样一种机制的存在,事件处理方法甚至允许为动态创建的对象定义事件。例如:

_root.attachMovie("symbolID", "newclip_mc", 10);

newclip_mc.onPress = function ()

{ trace("You pressed me"); }

另外一种事件处理的机制称为事件侦听。事件侦听需要了解两个概念:侦听器对象(listener object)和广播对象(broadcaster object)。广播对象需要一个addListener()方法把自己注册到侦听器对象。侦听器对象对广播对象的事件进行侦听,侦听到事件发生后,调用相关的方法进行处理。其过程如图所示:

事件监听

事件侦听提供了一种更加灵活的事件接收和处理机制。例如可以定义MC对象来接受Stage对象的onRelease事件,或者可以用Button对象来接收TextField对象的onChange事件。另外还可以把多个广播对象与一个侦听器对象关联,也可以把多个侦听器对象与一个广播对象相关联。在使用事件侦听时需要注意,事件的处理者不可以是事件的发生者。使用事件侦听的基本方法如下:

listenerObject.eventName = function()

{

// 处理代码

};

broadcastObject.addListener(listenerObject);

另外在开发时比较常用的是按钮和电影剪辑的事件处理。在电影剪辑和按钮中使用on() onClipEvent() 可以直接加入事件处理程序:

on(press)

{

       trace("Press") ;

}

on() 用于按钮事件,onClipEvent()用于电影剪辑事件。当然,在电影剪辑中也可以使用on()来处理按钮事件。在程序中,可以同时为多个事件指定处理方法,事件间用逗号隔开。使用这种方法来直接定义事件并不与事件处理方法矛盾,他们只是一个执行先后的问题。具体使用哪种方法定义事件也取决于个人的习惯。

事件处理代码也有生存期和作用域。事件处理中的代码(主要是变量)的生存期取决于事件定义方式。当使用事件处理方法和事件侦听时,由于都使用了函数,所以变量的生存期与函数中定义的变量的生存期是一致的。需要注意的是使用on() onClipEvent()定义事件处理时,定义的变量被认为是时间轴变量(无论是否使用了var声明)。如果在按钮的on()事件代码中使用了变量,那么该变量被认为是该按钮所在的时间轴的时间轴变量。也就是说,在电影剪辑实例中定义的变量属于该电影剪辑,而在按钮中使用的变量则属于按钮所在的时间轴,既它的_parent

在事件定义时,会经常使用this关键字,this关键字是对当前对象的引用。当使用不同的事件定义方式时,this有着不同的含义。在事件处理函数或事件侦听中,this指代了定义事件函数的对象。在on()或是onClipEvent()中使用this,如果所在对象是MC则指代当前的MC;如果在按钮中,则指代按钮所在的时间轴,既它的_parent。另外,按钮是不允许定义帧脚本的,在图形(Graphic)中允许定义帧脚本,但脚本不被编译和执行。

 

五、Actionscript2.0 中的OOP

对象通常可以从两个方面来描述:一个当前状态,它定义了对象当前的状态;另一个是行为,它定义了对象如何与外部输入交互。对于对象,可以建立一个模型,这个模型就称为类(Class)。模型仅仅实现对象的表示,而并非对象本身。而且每个模型都是按照特定的目的定义,并没有完全刻画对象的全部状态和行为。类是一种可以由程序员自己定义的数据类型,有的书上把这种数据类型称为类类型。类是由数据及其相关操作组成。也就是说类定义了数据类型和对这些数据所执行的操作类型。类包含的变量和方法通常称为类成员。在Actionscript2.0中,程序员可以在外部文件中自定义这种数据类型。Actionscrip2.0中的OOP并不是完全的OOP,只是部分的实现了OOP,因为它不支持类方法重载等。super关键字实现了子类中的代码对父类的引用。但是,Flash中的类与通常面向对象的程序语言中的类有比较大的差别,特别是那些基于时间轴的类。因为它的数据成员除了简单数据对象外还包括图形、声音、视频等对象,而且对象的生存期和作用域是基于时间轴的。类的方法也不仅仅是简单的数据处理,而是时间轴行为的表现——简单的说就是在时间轴上视听状态的变化。这也是Flash由本身的特点所决定的,因为Flash的侧重点在就于丰富媒体信息的表现,同时这也是RIA的一个基本特征。

Actionscript2.0中的类和接口只可以在外部文件中定义,当在发布、导出、测试、调试时,外部文件将被编译到swf文件中。所以如果对外部文件有所改动,则需要在保存后重新编译。类可以包含一个构造函数(Constructor),但并不包含析构函数(Destructor),这一点与Java类似——使用了一种自动的内存回收机制。类的构造函数是在创建类的实例时被自动调用的。构造函数的名称必须与它所在的类同名。如果没有为类定义构造函数,那么系统自动调用默认的构造函数。一个类只包含一个构造函数,构造函数不被重载。在构造函数中对数据进行初始化,也可以定义对象事件。下面的代码定义了一个Person类:

class Person

{

var Name:String="LeefangJie";

var Age:Number=23;

function Person (myName:String, myAge:Number)

{

       Name = myName;

       Age = myAge;

}

function Show():String

{

              return("My Name is "+Name+",Age is" +Age );

}

}

在定义类的属性时,最好把它们定义在最开始的地方并且使用严格数据类型定义,以增加可读性。方法的定义类似于函数的创建,方法可以有参数和返回值。需要注意的是,类必须保存在外部文件中,并且类名称必须与它所在的AS文件同名。在默认情况下,类文件与Flash文档需要保存在同一目录下,当然Flash也会根据类路径(classpath)自动搜索类文件。

类定义完成后,就可以创建类的实例。new操作符用于创建类的实例。其语法相当简单,下面的语句创建了Person类:

var newPerson:Person = new Person("LeeFangJie", 23);

Actionscript2.0支持类的继承,使用extends关键字对类进行扩展。子类可以继承父类的方法和属性,子类也称为派生类,父类则称为基类。类继承的语法如下:

class subclass extends supperclass

{

//Body of class

}

这里指定了subclasssupperclass继承,子类将继承父类的所有方法和属性。在继承关系中,父类既可以是Flash内置的类也可以是用户自己定义的类。如果继承的是Flash内置的类那么这个子类同时也继承了它的方法和属性。父类中的方法还可以在子类中重新被定义,程序员可以根据需要重新定义一个从父类继承的方法,这样在子类中就隐藏了父类的方法。在Actionscript2.0中,多重继承是不被允许的,即一个子类继承多个父类的情况是不被允许的。Actionscript2.0还支持接口继承,其语法与类继承一致:interface iA extends interface iB {}

与其他面向对象的语言一样,Actionscript2.0的类中也可以对类成员进行访问限定。在默认情况下,类成员可以被另外一个类所访问,即所有的类成员在默认情况下都是public的。但是在某些情况下,类的成员并不需要被其它类所访问,这时就需要对类的成员做访问限制,使它们成为类的私有成员。使用private访问修饰符可以阻止其它类的访问。类的私有成员只被定义它的类以及定义它的类的子类所访问。所以类的私有成员只有在类级别上进行访问,而无法在实例级别上进行访问。

类还可以有静态成员,用static关键字声明。静态成员属于类本身的,不属于类的实例。静态成员是唯一的,创建对象时并不创建它的副本,并被类的所有对象所共享。如果要对类的静态成员进行访问则必须通过类名引用。Math类的成员都是静态成员,所以可以使用类名直接访问,而不需要另外创建类的实例。与之相对的是实例成员,它们属于类的实例,通过对象名进行访问。

类对于实例来说,被认为是静态的,所以在程序运行期间,类只有一份,而类的实例可以有多个副本。静态成员与实例成员间的访问是有限制的,静态的成员无法访问实例成员,而实例成员则可以访问静态成员。这样,类的静态成员是被类的所有实例所共享的。

在面向对象的语言中,接口用来声明类成员,但是不定义它的具体实现。在Actionscript2.中接口是由一些空方法组成的。在开发一个大的应用时,通常情况下,不同的类之间很少有联系,但是在有的时候必须提供一种机制使不同的类之间可以进行通信,这时可以通过接口定义来实现。接口是所有的类必须遵照的一个协议规定。

实现类与类之间通信的一种方法就是先定义一个包含所有方法的类,然后其它的类可以从这个类扩展继承。由于应用程序本身就是由一些无关的类组成,使用这种方法,强迫去定义这样一个通用类显然是不合适的。一个好的解决方法是接口的定义,在接口中声明那些即将会通信的方法,然后在具体的类中去实现这些方法。在很多时候,需要非常细心地设计类结构,但是当了解了接口以后,并在程序中使用它,接口可以使程序有更好的结构、可维护性和可扩展性。

接口由类实现,需要使用implements关键字。而且类必须实现当前接口、当前接口的基接口所声明的所有方法。以下是一个接口实现的代码:class B implements iAB{}。接口不可以有变量声明或是赋值操作,而且接口不可以包括大括号,接口仅仅只是方法声明。和类一样,接口定义了一种新的数据类型,任何实现接口的类都可以被认为是接口所定义的数据类型,这可以用来确定给定类是否是该接口的实现。

为了使用经定义好的类或者接口,Flash必须确定这些外部文件的位置。Flash 在其中搜索类和接口定义的那一组目录称为类路径(classpath)。当创建了一个外部文件时,必须把它保存到一个指定的路径下,或者是这个路径下的一个子文件夹里面,否则Flash就无法确定类或接口所在的位置。在类路径的目录中所创建的子文件夹称为包(package),用来组织类或者接口。

Flash有两种设置类路径的方法:全局类路径(global classpath)和文档级类路径(document-level classpath)。全局路径应用于外部的AS文件和FLA文件,在Preference对话框设置。文档级别的类路径只应用于Fla文件,在发布设置(Publish Setting)对话框进行设置。在默认情况下,全局类路径有两个:当前文档所在路径的相对路径以及Flash的安装路径。文档级别的类路径在默认的情况下为空。类文件被定义以后,就要在其它外部文件或Fla文件中被引用,在编译时,Flash要搜索这些类文件,首先它按照当前文档指定的文档级类路径查找,如果没有找到该文件或该类路径为空,Flash就使用全局类路径进行搜索,如果还是没有找到则发生编译错误。如果AS文件没有一个相关联的文档级类路径,那么Flash只在全局类路径进行搜索。

包(Package)是用来组织外部脚本文件的。包是一个包含了若干类文件的文件夹,包可以包含其他的包,就称为子包(SubPackage)。如果要引用包中的类,可以使用完全限定名,或使用import语句导入包。在脚本中使用包中的类,必许把它所在的包名作为前缀,即使用完全限定名,如果类位于最顶层的目录,那么它的完全限定名就是它的类名。指定包的路径时,使用点把包名隔开,包与包之间是有等级性的,点号用来说明嵌套的文件夹。使用import语句可以在脚本中导入一个包,也可以使用星号(*)导入包中的所有类。在代码中导入了包以后,在创建类的对象时就无须再使用完全限定名。

Flash Actionscript中,还有一类特殊的类,称为动态类(dynamic class)。默认情况下,类的属性和方法是固定的。也就是说,类的实例不能创建或访问该类原来未声明或定义的属性或方法,否则就会出现编译器错误。但在某些情况下,可能需要在运行时添加和访问原来类定义中未定义的属性或方法。这种访问可以通过dynamic 类限定符来实现。由于是动态类,因此不会出现编译器错误。这里需要注意的是,在没有使用严格数据类型定义的情况下,被创建的对象也被认为是动态的,可以创建新的对象成员。有趣的是,这种情况下甚至可以在运行时重新定义函数体,这也算是一定意义上的多态吧。

 

六、把类与库项目关联

Flash Actionscript中引入类和接口的目的在很大程度上是为了方便代码的组织管理。在早期的版本中,代码几乎都写在Fla文件中,而且代码非常的分散,切很难管理,可读性极差。而类的使用把很大一部分的代码甚至是全部代码从原来的帧脚本和事件脚本中分离出来。单独地在类中定义属性、事件和方法。

库项目与类的关联在库项目的Linkage对话框中定义。虽然,电影剪辑、按钮和图形都可以设置Linkage对话框,但是最常用和最核心的库项目还是电影剪辑。所以这里只讨论电影剪辑与类的关联。在Linkage对话框中,首先必须选中“作为脚本导出(Export for Actionscript)”选项,标识符(Identifier)指定了库项目的脚本引用名,脚本类(AS2.0 class)指定了与该库项目相关联的类。

在类定义时,关联到电影剪辑的类必须从MovieClip基类扩展,其原因也是显而易见的。由于时间轴是嵌套的组织关系,而且时间轴上的对象可以在编辑环境下创建或运行时动态地创建,要实现时间轴下子时间轴的控制,必须在类成员中定义其引用。在编辑状态和运行时都可以为实例指定一个名称,类中引用名的定义应该与该指定名称相同。对象的事件处理方法需要在构造函数中定义,事件处理方法的定义与函数的定义是一致的。另外,在类的构造函数中,也可以为该类的组成对象定义事件处理方法。但是这里要特别小心和注意this_parent的使用。_parent属性只有基于时间轴的对象才可以使用,否则引用无效。OnEnterFrame事件的持续帧频触发可以为帧脚本定义代码。

把类可库项目关联的方法比较简单。这个过程的侧重点还是在于库项目的创建和类文件的定义。另外,组件是那些已经被编译的电影剪辑,显然它们与类的关联是毫无意义的。
0 0

相关博文

我的热门文章

img
取 消
img