ActionScript - 全局自定义事件?

发布于 2024-10-14 20:12:38 字数 3104 浏览 5 评论 0原文

到目前为止,我需要处理自己的自定义事件的方法是向分派自定义事件的对象添加事件侦听器。虽然这种事件处理方法工作得很好,但我希望我的自定义事件可以全局访问,其中侦听对象不需要与调度事件的对象相同。

在此示例中,我的主要 Controller 类正在实例化并向显示列表添加 2 个精灵类:Square三角形。第四个也是最后一个类是一个名为 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 以更改颜色,但这正是我试图避免的限制。

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

up until now, the way i've been needing to handle my own custom events is by adding an event listener to the object that was dispatching the custom event. while this method of event handling works just fine, i've come to the point where i would like my custom events to be globally accessible, where the listening object does not need to be the same object that is dispatching the event.

in this example, my main Controller class is instantiating and adding to the display list 2 sprite classes: Square and Triangle. the 4th and final class is a custom event called ColorChangeEvent.

i'm attempting to dispatch a new ColorChangeEvent from the Square class, which uses a timer to dispatch a new random color once every second, while Triangle will listen for the dispatched event and change its fill color to the color that was dispatched by 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);
        }
    }
}

needless to say, this isn't working.

of course, i could add the event listener to the Square instance in the Controller class, who's event handler could pass that value to Triangle via a public function to change the color, but this is exactly the kind of limitation i'm trying to avoid.

it's not always easy to access and pass a value to a class from where the custom event is dispatched, which is why i'm looking for an actual global solution to handling custom events.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浅暮の光 2024-10-21 20:12:38

我已经使用这个类有一段时间了。要使用它,您可以在 square: 中执行此操作,

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

然后在 Triangle: 中执行此

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();
        }
    }
}

I have been using this class for some time now. To use it you would do this in square:

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

and then in your Triangle:

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

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

You can even pass the ColorChangeEvent instead of just the color.

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

And then

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

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

I removed a lot of code that is specific to my projects, so I am not 100% it is usable exactly as-is. But, you should be able to modify it to get it working correctly. If not, let me know and I can try to work it out with you.

This class handles additional things that I will not go into, though you are free to explore. Be aware, however, that anything that subscribes for event notification has a strong reference by the EventManager. That means that if you want to destroy something for garbage collection, you need to call EventManager.instance.cancel(ColorChangeEvent.CHANGE, handleColorChange) before the Triangle instances can be collected.

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();
        }
    }
}
旧城空念 2024-10-21 20:12:38

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

在任何想要分派事件的地方,我都会导入 EventDispatchSingleton,然后调用 EventDispatchSingleton.instance.dispatchEvent();

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

I got this to work by creating a singleton: EventDispatchSingleton that extends EventDispatcher. It's basically an empty singleton that provides the dispatchEvent and add/removeEventListener methods (these are automatically provided by extending EventDispatcher).

Anywhere I want to dispatch an event I import EventDispatchSingleton and then call EventDispatchSingleton.instance.dispatchEvent(<someEvent>);.

Then, wherever I want to listen to that event, I just import EventDispatchSingleton and call EventDispatchSingleton.instance.addEventListener(eventName, callback);

℡Ms空城旧梦 2024-10-21 20:12:38

您应该研究事件冒泡,具体来说,我认为您会发现事件传播的捕获阶段很有用。阅读Adobe LiveDocs 中的事件传播 。它位于 Flex 文档中,但它是关于 AS3 事件的。

另外Senulous 有一篇关于 Flash 事件冒泡的好文章

You should look into event bubbling, specificly I think you will find the Capturing phase of the event propagation useful. Take a read of Event propagation from Adobe LiveDocs. It's in the Flex docs, but it is about AS3 Events.

Also Senocular has a good post on Flash Event Bubbling.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文