8.3 事件机制的高级应用
8.3.1 事件的优先级别和弱引用
- 事件的优先级 :
默认情况下,Flex会按照监听器注册的顺序来调用监听函数。
使用addEventListener 函数的priority 来实现 监听函数的优先级。priority 为整数类型,数字越大,级别越高。级别最高的最先被调用。
已经存在的监听器,无法被修改优先级。
使用MXML添加的事件监听函数无法指定优先级别,将采用默认的级别。
给一个对象注册多个监听器,即使每个监听器的优先级别不同,但也无法保证后一个执行时前面的监听函数已经执行完毕。设计时,后面的函数不应该以前者执行完毕为条件。
使用addEventListener 函数的priority 来实现 监听函数的优先级。priority 为整数类型,数字越大,级别越高。级别最高的最先被调用。
已经存在的监听器,无法被修改优先级。
使用MXML添加的事件监听函数无法指定优先级别,将采用默认的级别。
给一个对象注册多个监听器,即使每个监听器的优先级别不同,但也无法保证后一个执行时前面的监听函数已经执行完毕。设计时,后面的函数不应该以前者执行完毕为条件。
- 事件的弱引用
使用addEventListener 函数的最后一个参数 useWeakReference 来实现 监听函数的弱引用。默认为false,表示不使用弱引用。
弱引用和垃圾回收机制有关。
创建临时函数 :
var tmpFunc:Function = function():void{ }
因为默认监听器使用的是强引用,所以如果使用了tmpFunc 函数,然后将tmpFunc = null,代表清空tmpFunc,只是tmpFunc 这个引用为null,但是tmpFunc 引用的函数还是存在内存中。
使用了弱引用后,如果一个对象只存在弱引用,在执行垃圾回收时会将这些对象从内存中清除。
垃圾回收有自己的规律,而且是有周期的,并不会在第一时间将系统中的垃圾资源回收。一般在资源缺乏的情况下进行。
建议:当事件监听函数不再需要时,一定不要忘记使用removeEventListener 方法删除监听函数。
弱引用和垃圾回收机制有关。
创建临时函数 :
var tmpFunc:Function = function():void{ }
因为默认监听器使用的是强引用,所以如果使用了tmpFunc 函数,然后将tmpFunc = null,代表清空tmpFunc,只是tmpFunc 这个引用为null,但是tmpFunc 引用的函数还是存在内存中。
使用了弱引用后,如果一个对象只存在弱引用,在执行垃圾回收时会将这些对象从内存中清除。
垃圾回收有自己的规律,而且是有周期的,并不会在第一时间将系统中的垃圾资源回收。一般在资源缺乏的情况下进行。
建议:当事件监听函数不再需要时,一定不要忘记使用removeEventListener 方法删除监听函数。
8.3.2 创建自定义事件
创建自定义事件包括创建事件对象和派发事件两个部分。
派发事件:
使用EventDispatche 的dispatchEvent 方法:
dispatchEvent(event:Event);
其中event参数就是创建的事件对象。
在需要派发的组件设置事件:
派发事件:
使用EventDispatche 的dispatchEvent 方法:
dispatchEvent(event:Event);
其中event参数就是创建的事件对象。
在需要派发的组件设置事件:
- 定义一个事件类型常量:
public const CLICK_IMAGE:String = "clickImage";
- 在监听函数中派发事件:
internal function clickImage():void{
dispatchEvent(new Event(CLICK_IMAGE, false));
}
dispatchEvent(new Event(CLICK_IMAGE, false));
}
- 为事件注册监听函数
<mx:Image click="clickImage()" />
然后再需要使用事件的主程序:
- 在程序初始化时为组件的事件注册监听器,事件类型跟组件的事件类型一致:
internal funtion initApp():void{
imgPanel.addEventListener(ImgPanel.CLICK_IMAGE, clickHandler);
}
imgPanel.addEventListener(ImgPanel.CLICK_IMAGE, clickHandler);
}
- 设置监听函数:
internal function clickHandler(evt:Event):void{}
如果需要使用自定义的事件对象:
- 创建自定义对象的类:
-
- 类必须继承Event
public class ImageEvent extends Event{}
-
- 定义事件类型常量:
public const CLICK_IMAGE:String = "clickImage";
-
- 定义需要传递的参数为类属性:
public var time:String;
-
- 在构造函数中,定义参数,用来接收数据,这个数据将被符给类属性:
function ImageEvent(when:String):void{
//必须调用父类的构造方法,相当于创建了一个Event对象。
super(ImgPanel.CLICK_IMAGE, false, false);
time = when;
}
//必须调用父类的构造方法,相当于创建了一个Event对象。
super(ImgPanel.CLICK_IMAGE, false, false);
time = when;
}
- 使用自定义事件对象:
- 在派发事件部分,使用自定义对象为事件对象派发出去,修改为:
dispatchEvent(new ImageEvent("这里是参数值"));
-
- 在主程序的监听函数就可以使用自定义对象的数据了:
nternal function clickHandler(evt:ImageEvent):void{
evt.time; //time就是我们在自定义对象定义的属性。
}
evt.time; //time就是我们在自定义对象定义的属性。
}
Date 类的使用:
var date:Date = new Date();
date.getHours():获得小时
date.getMinutes():获得分钟
使用Metadata 标签给组件添加元数据:使事件成为组件的一个特殊属性。
在组件中可以这样使用:
<mx:Metadata>
<!-- 为事件定义元数据 -->
[Event(name="clickImage", type="events.ImageEvent")]
</mx:Metadata>
这样在使用组件的标签,就会出现 clickImage 属性,自动完成addEventListener 的工作。
var date:Date = new Date();
date.getHours():获得小时
date.getMinutes():获得分钟
使用Metadata 标签给组件添加元数据:使事件成为组件的一个特殊属性。
在组件中可以这样使用:
<mx:Metadata>
<!-- 为事件定义元数据 -->
[Event(name="clickImage", type="events.ImageEvent")]
</mx:Metadata>
这样在使用组件的标签,就会出现 clickImage 属性,自动完成addEventListener 的工作。
8.3.3 侦听事件管理--让你的控件可拖拽
Flex 组件内置了处理拖拽事件的接口,甚至有些控件以及实现了拖拽功能:List、DataGrid、Menu、TileList、Tree。
关于拖拽的有关属性,是这些控件共有的,默认值都是false:
关于拖拽的有关属性,是这些控件共有的,默认值都是false:
- allowDragSelection:是否可拖拽
- allowMultipleSelection:是否可多选,如果可以,按Ctrl 添加元素,Shift 反选元素。
- dragEnabled:是否可以拖动子元素
- dragMoveEnabled:是否移动元素位置,而不是复制元素,建议将这个设置为true。如果设置为false,将出现重复数据。
- dropEnabled:是否可以将物体放置进来
拖动功能限于在相同类型的控件间使用,且不同控件数据源的数据结构必须可以兼容。
在Flex 中,有几个专门的对象供开发者处理拖拽事件:
- DragManager:mx.managers 包中,管理拖拽事件
- DragSource:mx.core 包中,是Flex 框架的核心成员,处理拖拽中的数据传递
- DragEvent::mx.events 包中,拖拽操作中的事件对象
拖拽操作中至少有两个对象:提供数据的对象,接收数据的对象。提供数据的对象按照前后顺序分为以下事件:
- mouseDown:鼠标按下
- mouseMove:鼠标移到
- dragComplete:鼠标释放。判断目标是否能接受数据,如果可以,拖放成功。
接受方的事件:
- dragEnter:被拖动对象移动到目标范围时
- dragOver:鼠标移动到目标上
- dragDrop:鼠标在目标上松开
- dragExit:对象被拖离目标范围
开始拖拽对象,doDrag方法初始化拖拽动作中的所有数据:
DragManager.doDrag(
dragInitiator:派发拖拽事件的目标对象
dragSource:拖拽中的数据源,用来传递数据。通过定义DragSource对象来设置数据源,该对象的方法 addData(obj, "name") 可以添加数据。然后使用dataForFormat("name") 来获取数据,使用前用hasFormat("name) 来判断是否存在该对象。
mouseEvent:鼠标事件对象,包含了拖拽事件开始时的鼠标信息
dragImage:可选,一个可视化的Flex 组件,用来代替目标对象的显示,将在拖拽过程中一直跟随鼠标。如果没有指定,默认会使用一个矩形来代替。
xOffset:x坐标位移量,默认0,表示dragImage 和 目标对象左端的距离
yOffset:y坐标位移量,默认0,表示dragImage 和 目标对象顶端的距离
imageAlpha:默认0.5,表示 dragImage 的透明度,0-1
allowMove:是否允许移动,默认true,实际上这个属性不影响动作
);
acceptDragDrop(traget:IUIComponent)
表示对象同意接受拖拽到数据,如果不接受,物体将无法再该对象上拖放。traget 为设置的对象。
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="initApp()"> <mx:Style source="style.css" /> <mx:Script> <![CDATA[ import mx.managers.DragManager; import mx.core.DragSource; import mx.events.DragEvent; internal function initApp():void{ img.addEventListener(MouseEvent.MOUSE_DOWN,dragHandler); // canvas_1.addEventListener(DragEvent.DRAG_ENTER,enterHandler); canvas_1.addEventListener(DragEvent.DRAG_DROP,dropHandler); } // internal function dragHandler(evt:MouseEvent):void{ //拖拽的对象 var dragTarget:Image=Image(evt.currentTarget); //创建拖拽数据源 var ds:DragSource = new DragSource(); var obj:Object = new Object(); obj.name = "Image"+Math.random()*100; ds.addData(obj,"image"); //创建拖拽过程中显示的对象,可以是任意的组件 var imgProxy:Image = new Image(); imgProxy.source = img.source; imgProxy.width = 72; imgProxy.height = 22; //开始拖拽 DragManager.doDrag(dragTarget, ds, evt, imgProxy,0,0,0.8); } // internal function enterHandler(evt:DragEvent):void{ DragManager.acceptDragDrop(Canvas(evt.target)); } internal function dropHandler(evt:DragEvent):void{ // var newImg:Image = new Image(); newImg.source = img.source; canvas_1.addChild(newImg); newImg.x = canvas_1.mouseX; newImg.y = canvas_1.mouseY; var obj:Object = evt.dragSource.dataForFormat("image"); newImg.toolTip = obj.name; } ]]> </mx:Script> <mx:Canvas id="canvas_1" styleName="box" x="50" y="150" width="265" height="231"> </mx:Canvas> <mx:Image id="img" x="51" y="97" source="FlexLogo.gif"/> </mx:Application>