ActionScript - 全局自定义事件?

时间:2011-01-28 01:25:17

标签: actionscript-3 events global dispatcher

到目前为止,我需要处理自己的自定义事件的方法是向调度自定义事件的对象添加事件侦听器。虽然这种事件处理方法运行得很好,但我已经到了这样的地步,我希望我的自定义事件可以全局访问,其中监听对象不需要是调度事件的同一对象。

在此示例中,我的主 Controller 类正在实例化并向显示列表添加2个精灵类: Square Triangle 。第四个也是最后一个类是一个名为 ColorChangeEvent 的自定义事件。

我正在尝试从Square类调度一个新的ColorChangeEvent,它使用一个计时器每秒调度一次新的随机颜色,而Triangle将监听调度的事件并将其填充颜色更改为调度的颜色由Square。

Controller.as:

package
{
import flash.display.Sprite;

public class Controller extends Sprite
    {
    public function Controller()
        {
        var sq:Square = new Square();
        sq.x = sq.y = 100;

        var tr:Triangle = new Triangle();
        tr.x = tr.y = 250;

        addChild(sq);
        addChild(tr);
        }
    }
}

Square.as:

package
{
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;

    public class Square extends Sprite
        {
        public function Square()
            {
            graphics.beginFill(0x999999);
            graphics.drawRect(0, 0, 100, 100);
            graphics.endFill();

            var myTimer:Timer = new Timer(1000);
            myTimer.addEventListener(TimerEvent.TIMER, dispatchNewColor);
            myTimer.start();
            }

        private function dispatchNewColor(evt:TimerEvent):void
            {
            var randomColor:Number = Math.random() * 0xFFFFFF;
            trace("Square Class Dispatched: " + randomColor);

            dispatchEvent(new ColorChangeEvent(ColorChangeEvent.CHANGE, randomColor));
            }
        }
    }

Triangle.as:

package
{
import flash.display.Sprite;
import flash.geom.ColorTransform;

public class Triangle extends Sprite
    {
    public function Triangle()
        {
        graphics.beginFill(0x999999);
        graphics.moveTo(0, 0);
        graphics.lineTo(100, 50);
        graphics.lineTo(-50, 150);
        graphics.endFill();

        addEventListener(ColorChangeEvent.CHANGE, changeColor);
        }

    private function changeColor(evt:ColorChangeEvent):void
        {
        var ct:ColorTransform = new ColorTransform;
        ct.color = evt.color;

        transform.colorTransform = ct;

        trace("Triangle Class Received: " + evt.color);
        }
    }
}

ColorChangeEvent.as:

package
{
import flash.events.Event;

public class ColorChangeEvent extends Event
    {
    public static const CHANGE:String = "change";
    public var color:Number;

    public function ColorChangeEvent(type:String, color:Number) 
        {
        super(type);
        this.color = color;
        }

    override public function clone():Event
        {
        return new ColorChangeEvent(type, color);
        }
    }
}
不用说,这不起作用。

当然,我可以将事件监听器添加到Controller类中的Square实例,谁的事件处理程序可以通过公共函数将该值传递给Triangle来改变颜色,但这正是我的限制试图避免。

访问并将值传递给调度自定义事件的类并不总是很容易,这就是为什么我正在寻找处理自定义事件的实际全局解决方案。

3 个答案:

答案 0 :(得分:4)

我一直在使用这门课。要使用它,你可以在方块中执行:

data.EventManager.instance.publish("someName", randomColor);

然后在你的三角形中:

data.EventManager.instance.subscribe("someName", handleColorChange);

private function handleColorChange(color:Number):void {
    // implementation here
}

您甚至可以传递ColorChangeEvent而不仅仅是颜色。

data.EventManager.instance.publish(ColorChangeEvent.CHANGE, new ColorChangeEvent(ColorChangeEvent.CHANGE, randomColor);

然后

data.EventManager.instance.subscribe(ColorChangeEvent.CHANGE, handleColorChange);

private function handleColorChange(colorChangeEvent:ColorChangeEvent):void {
    // implement here
}

我删除了很多特定于我的项目的代码,所以我不是100%它完全可以使用。但是,您应该能够修改它以使其正常工作。如果没有,请告诉我,我可以尝试与您合作。

这个课程处理我不会涉及的其他内容,尽管你可以自由探索。但请注意,订阅事件通知的任何内容都有EventManager的强引用。这意味着如果你想破坏垃圾收集的东西,你需要在收集Triangle实例之前调用EventManager.instance.cancel(ColorChangeEvent.CHANGE, handleColorChange)

package data {
    import flash.utils.*;

    public class EventManager extends Object {
        private var _subscribers:Dictionary;
        private var _calls:Dictionary;
        private var _feeds:Dictionary;
        private var _requests:Dictionary;
        private var _notify:Dictionary;
        private var _services:Dictionary;
        private static var __instance:EventManager;

        public function EventManager() {
            if (__instance) {
                trace("EventManager is a Singleton class which should only be accessed via getInstance()");
            }
            _feeds = new Dictionary(true);
            _subscribers = new Dictionary(true);
            _requests = new Dictionary(true);
            _services = new Dictionary(true);
            _notify = new Dictionary(true);
        }

        public function getFeedData($name:String) {
            if (_feeds[$name]) {
                return _feeds[$name];
            }
            return undefined;
        }


        public function unpublish($name:String) {
            var _post:* = _feeds[$name];
            delete _feeds[$name];
            return _post;
        }

        public function cancel($name:String, $subscriberFunc:Function, ...args): void {
            var _cnt:Number;
            var _subscriberArray:Array;
            if (_subscribers[$name]) {
                for (_cnt = 0; _cnt < _subscribers[$name].length; _cnt++) {
                    if (_subscribers[$name][_cnt] == $subscriberFunc) {
                        _subscribers[$name].splice(_cnt, 1);
                    }
                }
            }

            if (_requests[$name]) {
                _subscriberArray = _requests[$name];
                _cnt = _subscriberArray.length;

                while (_cnt > 0) {
                    if (_subscriberArray[_cnt] == $subscriberFunc) {
                        _subscriberArray.splice(_cnt, 1);
                    }
                    _cnt--;
                }
            }
        }

        public function subscribe($name:String, $subscriber:Function, ...args): void {
            var _funcArray:Array;
            var _func:Function;


            if (_feeds[$name]) {
                $subscriber(_feeds[$name]);
            }

            if (! _subscribers[$name]) {
                _subscribers[$name] = new Array();
            }
            _subscribers[$name].push($subscriber);

            if (_notify[$name]) {
                _funcArray = _notify[$name];

                for each (_func in _funcArray) {
                    _func();
                }
                delete _notify[$name];
            }
        }

        public function request($name:String, $feedFunction:Function): void {
            var _requestArray:Array;
            var _request:Function;

            if (! _feeds[$name]) {
                if (! _requests[$name]) {
                    _requests[$name] = new Array();
                }
                _requests[$name].push($feedFunction);
            } else {
                $feedFunction(_feeds[$name]);
            }

            if (_notify[$name]) {
                _requestArray = _notify[$name];

                for each (_request in _requestArray) {
                    _request();
                }
                delete _notify[$name];
            }
        }

        public function publish($name:String, $data:*, $args:Object = null): void {
            var _subscriberArray:Array;
            var _func:Function;
            var cnt:Number = 0;
            _feeds[$name] = $data;

            if (_subscribers[$name] != undefined) {
                _subscriberArray = _subscribers[$name].slice();
                _cnt = 0;

                while (_cnt < _subscriberArray.length) {
                    _func = _subscriberArray[_cnt] as Function;

                    if ($args) {
                        _func($data, $args);
                    }else {
                        _func($data);
                    }
                    _cnt++;
                }
            }

            if (_requests[$name]) {
                _subscriberArray = _requests[$name].slice();
                delete _requests[$name];
                _cnt = 0;

                while (_cnt < _subscriberArray.length) {
                    if (_subscriberArray[_cnt] != null) {
                        _subscriberArray[_cnt]($data);
                    }
                    _cnt++;
                }
            }
        }

        public function notify($name:String, $subscriber:Function): void {
            if (_requests[$name] || _subscribers[$name]) {
                $subscriber();
            }else {
                if (! _notify[$name]) {
                    _notify[$name] = new Array();
                }
                _notify[$name].push($subscriber);
            }
        }


        public static function getInstance(): EventManager {
            if (! __instance) {
                __instance = new EventManager();
            }
            return __instance;
        }

        public static function get instance(): EventManager {
            return getInstance();
        }
    }
}

答案 1 :(得分:1)

我通过创建一个EventDispatchSingleton extends EventDispatcher来实现这一点。它基本上是一个空的单例,它提供了dispatchEvent和add / removeEventListener方法(通过扩展EventDispatcher自动提供这些方法)。

我要发送事件的任何地方我导入EventDispatchSingleton然后调用EventDispatchSingleton.instance.dispatchEvent(<someEvent>);

然后,无论我想听哪个事件,我只需导入EventDispatchSingleton并调用EventDispatchSingleton.instance.addEventListener(eventName, callback);

答案 2 :(得分:0)

你应该调查事件冒泡,具体来说我认为你会发现事件传播的捕获阶段很有用。阅读Event propagation from Adobe LiveDocs。它在Flex文档中,但它与AS3事件有关。

Senocular has a good post on Flash Event Bubbling