Chapter 4: About Event--Using events
2010年09月28日
在Flex中使用事件分为两步:第一步,在mxml中写个方法或者在类中写个类方法,这个方法也就是来响应事件的事件监听器或者事件处理者。该方法经常访问Event对象的一些属性或者应用状态的一些其他设置。该方法通常包括一个指定被传进来的某种事件类型的参数。 下面的例子展示了一个简单的事件监听函数,当一个控件触发了这个函数正在监听的事件。
正如你在例子中所看到,你可以用display list 对象通过addEventListener()方法来注册一个方法。 大多数Flex控件简化了监听器的注册,通过在MXML标签中来指定监听器。例如,通过了的click属性来指定了事件监听器而不是用addEventListener() 方法。
这等价于上个例子中的 addEventListener()方法。可是最好还是练习使用addEventListener()方法。因为这个方法能够通过让你设置优先级和捕获的设置和使用event的常量,从而让你有能更好的控制事件。 此外,如果你使用addEventListener()方法来添加事件监听器,你可以通过 removeEventListener()方法来移除这个监听器,如果你是在标签中使用事件属性的方式添加的事件监听器,你不能使用
removeEventListener() 来移除这个监听器。
每次当一个控件产生一个事件时,Flex创建一个包含关于那个事件的信息Event对象,该信息中包括了事件的类型和派发该事件的控件的引用。为了能够使用这个Event对象,你指定它作为事件处理方法的一个参数,如下面的例子。 如果你想要在事件处理方法中访问一个通过内嵌式写法(就是直接写在MXML标签中)而出发的Event对象,你必须在MXML标签中增加event关键字一遍Flex可以隐式的传递给事件处理方法。如下所示:
有时候你不需要在处理函数中使用event对象 ,下面的例子创建了两个事件处理函数并用ComboBox控件注册了它们,第一个函数
openEvt(),没有任何参数。第二个 函数changeEvt(),有一个Event类型的参数,在函数内使用事件对象来访问ComboBox控件的值和
selectedIndex ComboBox open="openEvt()" change="changeEvt(event)"> AK AL AR 指定Event对象
你为监听器函数指定一个Event类型的参数,如下
function myEventListener(e:Event):void { ... } 可是如果你想访问具体的派发事件的属性时,你必须指定一个更具体的事件类型,例如ToolTipEvent 或者 KeyboardEvent,见下:
import mx.events.ToolTip function myEventListener(e:ToolTipEvent):void { ... }
In some cases, you must import the events class in your ActionScript block
Most objects have specific events that are associated with them, and most of them can dispatch more than one
type of event.
If you declare an event of type Event, you can cast it to a more specific type to access its event-specific properties. 某些时候,你必须在Actionscript代码块中引入该事件类。大多数的对象都有和它们相关联的事件,而且他们的当中的多数能派发一个以上的事件类型。
访问event.currentTarget属性 Event对象包含了派发事件的组件的实例的引用,这意味着你可以在事件监听函数中访问该实例所有的属性和方法。下面的例子展示了访问出发事件的Button控件的id属性。
你可以访问 currentTarget的成员。如果你不把currentTarget强制转换成一个具体的类型,编译器就把它作为Object类型,Object可以有任何属性和方法因为在Actionscript中Object类是动态的。因此,当你访问currentTarget的属性和方法时,最好把它转换为你所认为的将能派发事件的类型。这将在编译期给你强类型检查从而能帮助你避免在运行时抛出run-time异常。下面的例子在调用setSelection()方法前把currentTarget转换为TextInput类型,而在设置tmesis属性前没有强转,tmesis属性其实在TextInput类中不存在的。为的是说明如果你没有强转的话,当你试图访问不存在的成员时你将会看到一个run-time异常而不是complie-time错误,而如果你把currentTarget转换成一个具体的类型的话,类型检查就会发生,就可以避免发生这种错误。 你也可以把currentTarget强转成UIComponent或者一些其他的泛类,这些类仍然有display objects的方法。通过这种方式,即使你不确切的知道哪个控件将会派发出事件,至少你可以确保有些类型检查。
你也可以访问这个包含当前节点的引用的target属性的属性和方法, (没明白什么意思。。。。。。。)
注册事件监听函数
有许多方式注册事件监听器。 1、写死式(哈哈)
2 、用addEventListener()方法
正如以前的例子,不论用户什么时候单机这个Button按钮,Flex都将调用myClickHandler()函数。可是,用这种方法注册监听器提供了更多的灵活性。你可以为一个事件监听器注册多个组件,一个组件添加多个事件监听器,或者移除它们。
3 、 创建一个事件监听类,用这个类来监听该组件的事件。这种方法提高了代码的重用性,使你能够在MXML文件外集中处理事件。
在标签中定义event事件监听器 在Flex应用中定义事件监听器的最简单的方法是在组件的MXML标签中指定一个事件监听函数。在一个组件的事件属性中加上Actionscript语句或者指定一个事件处理函数。
事件处理函数可以包含任何有效的Actionscript代码, 可以包含全局的方法,如下例: 在写死式中有一个特殊的参数, event参数。如果你把event加入到参数列表,Flex会传递这个event对象,在你的事件监听器中可以访问这个event对象的所有属性,下面的例子把event传递到submitForm()函数中,然后把它具体化为MouseEvent类型。
当你使用写死式的方式添加事件监听函数时,在传递参数时最好还是把event这个关键字传过去,并且在事件监听函数的参数类型中指明一个最准确的Event类型,比如用MouseEvent而不用Event。你可以使用event对象来访问事件源的引用,事件的类型(比如click)或者其他相关的属性。比如是一个list-based控件的话可以访问它的row number和值。你也可以使用event对象来访问事件源组件的属性和方法。尽管你大多数时候是将整个Event对象传递给事件监听函数,你也可以传递event的某个单独的属性,如下例子:
使用写死式这种方式没有使用addEventListener()方法灵活。缺点是你不能给event对象设置useCapture或者priority属性并且一旦你添加之后,你将不能移除它。
使用addEventListener() 方法
b1.addEventListener(MouseEvent.CLICK, myClickListener); addEventListener() 方法通常格式如下:
componentInstance.addEventListener(event_type:Stri ng, event_listener:Function,use_capture:Boolean, priority:int, weakRef:Boolean)
event_type该参数是组件派发的事件类型。它可以是事件类型的字符串(比如"click"或者"mouseOut")也可以是一个静态常量(比如MouseEvent.CLICK 或者 MouseEvent.MOUSE_OUT)。这个参数是必须的。
静态常量提供了指定事件类型的更简单的方式,你应该使用常量而不是字符串因为如果你一不小心拼错了常量的名字编译器会捕捉到错误,但是如果你写错了字符串的话属于书写上的错误,调试会更加困难并且可能导致意外的行为。
You should use the constants wherever possible. For example, when you are testing to see whether an Event object
is of a certain type, use the following code:
if (myEventObject.type == MouseEvent.CLICK) {/* your code here */}
Do not use the following code:
if (myEventObject.type == "click") {/* your code here */}
The event_listener argument is the function that handles the event. This argument is required.use_capture parameter of the addEventListener() method lets you control the phase in the event flow in which your listener will be active. It sets the value of the useCapture property of the Event object. If useCapture is set to true, your listener is active during the capturing phase of the event flow. If useCapture is set to false, your listener is active during the targeting and bubbling phases of the event flow, but not during the capturing phase. The default value is determined by the type of event, but is false in most cases. addEventListener() twice, once with the To listen for an event during all phases of the event flow, you must call useCapture parameter set to true, and again with use_capture set to false. This argument is optional.
addEventListener() 的use_capture参数让你可以控制监听器在事件流中的3个时期何时应该被触发。如果useCapture属性设置为true,事件监听函数在事件流的捕获阶段被触发,如果useCapture被设置为false,事件监听器将会在目标和冒泡阶段被触发,默认值取决于该事件类型,但是大多数时候默认值是false,
为了监听事件流的所有阶段,你必须把useCapture设置为true,然后重新把use_capture设置为false,
priority参数设置了事件监听器的优先级,对于同一个事件来说,数字越高,相当于其他的执行的越早。同一优先级按照它们被添加的顺序依次执行,priority参数默认值为0,但是你可以给它赋值为负数或正数,如果几个事件监听函数没有设置优先级而被添加进去,越早被添加的执行的越早。
weakRef属性为你提供了控制内存资源的功能,强引用(当weakRef是false时)可以避免监听器被垃圾回收。若引用(当weakRef是true时)则相反,默认值是false,当你添加了一个监听函数并且该函数被唤醒时,Flex隐式的创建Event对象然后把它传递给监听函数,你必须在函数声明时定义该参数。
b1.addEventListener(MouseEvent.CLICK, performAction);
In the listener function, you declare the Event object as a parameter, as follows:
public function performAction(e:MouseEvent):void {
...
}
The following example defines a new handler function myClickListener(). It then registers the click event of the Button control with that handler. When the user clicks the button, Flex calls the myClickHandler() function. Using addEventListener() inside an MXML tag
You can add event listeners with the addEventListener() method inline with the component definition. The following Button control definition adds the call to the addEventListener() method inline with the Button controls initialize property: 在MXML标签中使用addEventListener()方法
可以在组件的定义中使用addEventListener()添加事件监听器,下面的例子在Button控件的initialize属性中调用addEventListener()方法添加监听器,
这等价于写死式,可是用addEventListener()可以让你设置useCapture and priority属性,此外写死式不能移除监听器,可是用addEventListener()方式可以移除。 Using nested inner functions as event listeners
Rather than passing the name of an event listener function to the addEventListener() method, you can define
an inner function (also known as a closure).
In the following example, the nested inner function is called when the button is clicked:
Function closures are created any time a function is executed apart from an object or a class. They retain the scope
in which they were defined. This creates interesting results when a function is passed as an argument or a return
value into a different scope. For example, the following code creates two functions:
foo(), which returns a nested function named rectArea() that calculates the area of a rectangle, and bar(), which calls foo() and stores the returned function closure in a variable named myProduct. Even though the bar() function defines its own local variable x (with a myProduct() is called, it retains the variable x (with a value of 40) defined
value of 2), when the function closure in function foo(). The bar() function therefore returns the product of the numbers in the TextInput controls, rather than 8.
If the listener that you pass to addEventListener() method is a nested inner function, you should not pass true
useWeakReference argument. For example:
for the
addEventListener("anyEvent",
function(e:Event) { /* My listener function. */ },
false, 0, true);
In this example, passing true as the last argument can lead to unexpected results. To Flex, an inner function is
actually an object, and can be freed by the garbage collector. If you set the value of the
useWeakReference
argument to
true, as shown in the previous example, there are no persistent references at all to the inner function.
The next time the garbage collector runs, it might free the function, and the function will not be called when the
event is triggered.
If there are other references to the inner function (for example, if you saved it in another variable), the garbage
collector will not free it.
Regular class-level member functions are not subject to garbage collection; as a result, you can set the value of the
useWeakReference argument to true and they will not be garbage collected.
Removing event handlers
It is a good idea to remove any handlers that will no longer be used. This removes references to objects so that they
can be cleared from memory. You can use the
removeEventListener() method to remove an event handler that
you no longer need. All components that can call
addEventListener() can also call the
removeEventListener() method. The syntax for the removeEventListener() method is as follows:
componentInstance.removeEventListener(event_type:S tring, listener_function:Function,
use_capture:Boolean)
For example, consider the following code:
myButton.removeEventListener(MouseEvent.CLICK, myClickHandler);
The event_type and listener_function parameters are required. These are the same as the required param-
eters for the
addEventListener() method.
use_capture parameter is also identical to the parameter used in the addEventListener() method. Recall
The
that you can listen for events during all event phases by calling
addEventListener() twice: once with
use_capture set to true, and again with it set to false. To remove both event listeners, you must call
removeEventListener() twice: once with use_capture set to true, and again with it set to false.
addEventListener() method in an ActionScript
You can remove only event listeners that you added with the
block. You cannot remove an event listener that was defined in the MXML tag, even if it was registered using a
call to the
addEventListener() method that was made inside a tag attribute.
The following sample application shows what type of handler can be removed and what type cannot:
Creating event handler classes
You can create an external class file and use the methods of this class as event handlers. Objects themselves cannot
be event handlers, but methods of an object can be. By defining one class that handles all your event handlers, you
can use the same event handling logic across applications, which can make your MXML applications more readable and maintainable.
To create a class that handles events, you usually import the flash.events.Event class. You also usually write an empty constructor. The following ActionScript class file calls the Alert controls show() method whenever it handles an event with the handleAllEvents() method: 创建一个事件处理类
你可以创建一个外部类文件,把它当中的方法作为事件处理函数,对象本身并不能作为事件处理函数,但是对象的方法可以。通过定义一个类来处理你的所有的事件处理函数,可以在整个应用中应用同一个事件处理逻辑,这将会使你的MXML应用可读性和维护性带来提升。 创建一个这样的类,通常是引入flash.events.Event类,然后写一个空的构造函数,下面的类文件每当它的handleAllEvents() 方法处理一个事件时,都会调用Alert的show()方法,
// events/MyEventHandler.as package { // Empty package. import flash.events.Event; import mx.controls.Alert; public class MyEventHandler { public function MyEventHandler() { // Empty constructor. } public function handleAllEvents(event:Event):void { Alert.show("Some event happened."); } } }
In your MXML file, you declare a new instance of MyEventHandler and use the addEventListener() method to register its handleAllEvents() method as a handler to the Button controls click event, as the following example shows: 在你的XMML文件中,你可以定义一个MyEventHandler类的实例,用addEventListener()方法来注册它当中的handleAllEvents() 方法作为Buttion控件的click事件的事件监听函数。如下例子所示:
The best approach is to define the event handlers method as static. When you make the event handler method
static, you are not required to instantiate the class inside your MXML application. The following
createHandler() function registers the handleAllEvents() method as an event handler without instantiating
the MyStaticEventHandler class: 最好是把类中的想要作为事件监听器的方法定义为static,好处是在MXML应用中不需要实例化这个类,下面的createHandler() 方法注册了handleAllEvents()作为事件监听器,而没有实例化这个MyStaticEventHandler类,
In the class file, you just add the static keyword to the method signature: // events/MyStaticEventHandler.as package { // Empty package. import flash.events.Event; import mx.controls.Alert; public class MyStaticEventHandler { public function MyStaticEventHandler() { // Empty constructor. } public static function handleAllEvents(event:Event):void { Alert.show("Some event happened."); } } }
Store your event listener class in a directory in your source path. You can also store your ActionScript class in the
same directory as your MXML file, although Adobe does not recommend this. 为一个事件注册多个事件监听器 你有两种方式来为一个事件注册多个事件监听器,当你用写死式的方法来注册多个监听器的时候,可以用";"分号把他们隔开,下面的例子展示了为click事件注册了submitForm() 和 debugMessage()这两个函数,
通过调用addEventListener()方式,可以多次调用addEventListener()方法来添加多个处理函数。下面的例子为b1s的click事件住了submitForm() and debugMessage()监听方法, 你可以结合起来使用这两种方法,下面的例子展示了 :为一个Button控件通过写死式注册了一个click事件监听函数 performAction(),在performAction()方法中,按照CheckBox控件的状态条件给它添加了第二个click事件监听器logAction(),
You can set the order in which event listeners are called by using the priority parameter of the
addEventListener() method. You cannot set a priority for a listener function if you added the event listener
using MXML inline. For more information on setting priorities, see Event priorities on page . 给多个组件注册同一个事件监听器 你可以给同一个组件的多个事件或者不同组件的多个事件注册同一个事件监听器,下面的例子给两个不同的button注册了一个监听函数submitForm():
当你用addEventListener() 方法来为多个组件的事件注册同一个事件监听器的时候,你必须为每一个组件的实例都调用addEventListener() 方法。如下:
如果你这样做的话,你应该在事件监听函数中加上处理事件类型的逻辑代码,事件源的引用已经被添加在了Event对象上了,不管什么触发的这个事件,你都能基于Event对象的target或者type属性来条件化事件处理的过程。Flex在所有的event对象上都添加上了这两两个属性,下面的例子为Button的click事件和CheckBox的click事件注册了myEventHandler()事件监听函数,为了发现调用该事件监听的对象类型,函数中用case语句检查event对象的中的target的className属性。 给监听函数传递额外的参数
能不能给监听函数传递额外的参数取决你是怎样注册它的,如果你是用addEventListener()方法注册的,你不能给它传递多余的参数,而且那个事件监听函数只可以声明一个参数,就是Event对象(或者它的子类),举个例子,下面的例子将会报错因为 clickListener()方法需要传递两个参数。
public function addListeners():void { b1.addEventListener(MouseEvent.CLICK,clickListener ); } public function clickListener(e:MouseEvent, a:String):void { ... }
因为addEventListener() 方法的第二个参数是个function类型,所以你不能在调用addEventListener() 时为那个函数具体指定参数,为了能够传递更多的参数给监听函数,你必须在监听函数中已经声明了它们,然后then call the final method with those parameters. 如果你是通过写死式注册了事件监听器,你可以给它传递任意多个参数,只要你在定义监听函数的时候参数列表中已经声明了它们,就可以传递,下面的例子给runMove()监听函数传递了一个字符串。