Есть ли способ удалить неизвестные слушатели событий из объектов? - PullRequest
6 голосов
/ 08 октября 2008

Я хочу иметь кнопку многоразового использования, которую можно зарегистрировать для одного из множества различных обратных вызовов, определяемых внешним источником. Когда новый обратный вызов установлен, я хочу удалить старый. Я также хочу иметь возможность очищать обратный вызов извне в любое время.

public function registerButtonCallback(function:Function):void
{
  clearButtonCallback();

  button.addEventListener(MouseEvent.CLICK, function, false, 0, true);
}

public function clearButtonCallback():void
{
  if (button.hasEventListener(MouseEvent.CLICK) == true)
  {
    // do something to remove that listener
  }
}

Я видел предложения по использованию «arguments.callee» в обратном вызове, но я не хочу привязывать эту функциональность к обратному вызову - например, я мог бы хотеть иметь возможность дважды нажать кнопку .

Предложения

Ответы [ 8 ]

8 голосов
/ 08 октября 2008

Я предполагаю, что вы хотите только одну функцию обратного вызова в любой момент времени. Если это так, то почему бы не иметь единственную функцию обратного вызова, связанную с событием click на кнопке, которая сама вызвала функцию, и чтобы эта функция была настраиваемой ...

<mx:Button click="doCallback()" .../>

public var onClickFunction:Function = null;
private function doCallback():void
{
    if (onClickFunction != null)
    {
        onClickFunction(); // optionally you can pass some parameters in here if you match the signature of your callback
    }
}

Потребитель вашего элемента управления, в котором находится ваша кнопка, установит функцию onClickFunction с соответствующей функцией. На самом деле вы можете установить его так часто, как вам нравится.

Если вы хотите пойти еще дальше, вы можете создать подкласс класса AS3 Button и обернуть все это внутри него.

4 голосов
/ 20 ноября 2009

Нет. Вы должны держать ссылку на слушателя, чтобы удалить его. Если вы заранее не сохранили ссылку на функцию прослушивателя, не существует документированного открытого метода для получения такой ссылки из EventDispatcher.

addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
dispatchEvent(event:Event):Boolean
hasEventListener(type:String):Boolean
removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
willTrigger(type:String):Boolean 

Как вы можете видеть, есть два метода, чтобы сообщить вам, зарегистрирован ли слушатель типа события или один из его родителей зарегистрировал слушателя, но ни один из этих методов не возвращает список зарегистрированных слушателей.

Теперь, пожалуйста, извините Adobe за написание такого бесполезного API. По сути, они дают вам возможность узнать, «изменился» ли поток событий, но не дают вам ничего сделать с этой информацией!

3 голосов
/ 13 октября 2008

Храните слушателя как опору. Когда добавляется другое событие, проверьте, существует ли прослушиватель, и если это так, вызовите removeEventListener.

Либо переопределите метод addEventListener вашей кнопки. Когда вызывается addEventListener, сохраняйте замыкание перед добавлением его к событию в объекте Dictionary. Когда addEventListener вызывается снова, удалите его:


var listeners:Dictionary = new Dictionary();</p>

<p>override public function addEventListener( type : String, listener : Function, useCapture : Boolean = false, priority : int = 0, useWeakReference : Boolean = false) : void {</p>

<pre><code>  if( listeners[ type ] ) {

     if( listeners[ type ] [ useCapture ] {

        //snip... etc: check for existence of the listener

        removeEventListener( type, listeners[ type ] [ useCapture ], useCapture );

        listeners[ type ] [ useCapture ] = null;

        //clean up: if no listeners of this type exist, remove the dictionary key for the type, etc...

     }

  }

  listeners[ type ] [ useCapture ] = listener;

  super.addEventListener( type, listener, useCapture, priority, useWeakReference );

};

2 голосов
/ 01 августа 2010

Я написал для этого подкласс EventCurb, см. Мой блог здесь или вставьте ниже.

package
{
   import flash.events.EventDispatcher;
   import flash.utils.Dictionary;
   /**
    * ...
    * @author Thomas James Thorstensson
    * @version 1.0.1
    */
   public class EventCurb extends EventDispatcher
   {
      private static var instance:EventCurb= new EventCurb();
      private var objDict:Dictionary = new Dictionary(true);
      private var _listener:Function;
      private var objArr:Array;
      private var obj:Object;

      public function EventCurb() {
         if( instance ) throw new Error( "Singleton and can only be accessed through Singleton.getInstance()" );
      }

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

      override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
      {
         super.addEventListener(type, listener, useCapture, priority, useWeakReference);
      }

      override public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
      {
         super.removeEventListener(type, listener, useCapture);
      }

      public function addListener(o:EventDispatcher, type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void {
         // the object as key for an array of its event types
         if (objDict[o] == null)  objArr = objDict[o] = [];
         for (var i:int = 0; i <  objArr.length; i++) {
            if ( objArr[i].type == type)
            trace ("_______object already has this listener not adding!")
            return
         }
         obj = { type:type, listener:listener }
         objArr.push(obj);
         o.addEventListener(type, listener, useCapture, priority, useWeakReference);
      }

      public function removeListener(o:EventDispatcher, type:String, listener:Function, useCapture:Boolean = false):void {
         // if the object has listeners (ie exists in dictionary)
         if (objDict[o] as Array !== null) {
            var tmpArr:Array = [];
            tmpArr = objDict[o] as Array;
            for (var i:int = 0; i < tmpArr.length; i++) {
               if (tmpArr[i].type == type) objArr.splice(i);
            }

            o.removeEventListener(type, listener, useCapture);
            if (tmpArr.length == 0) {
               delete objDict[o]
            }
         }else {
            trace("_______object has no listeners");
         }
      }

      /**
       * If object has listeners, returns an Array which can be accessed
       * as array[index].type,array[index].listeners
       * @param   o
       * @return Array
       */
      public function getListeners(o:EventDispatcher):Array{
         if (objDict[o] as Array !== null) {
            var tmpArr:Array = [];
            tmpArr = objDict[o] as Array;
            // forget trying to trace out the function name we use the function literal...
            for (var i:int = 0; i < tmpArr.length; i++) {
               trace("_______object " + o + " has event types: " + tmpArr[i].type +" with listener: " + tmpArr[i].listener);
            }
            return tmpArr

         }else {
            trace("_______object has no listeners");
            return null
         }

      }

      public function removeAllListeners(o:EventDispatcher, cap:Boolean = false):void {
         if (objDict[o] as Array !== null) {
            var tmpArr:Array = [];
            tmpArr = objDict[o] as Array;
            for (var i:int = 0; i < tmpArr.length; i++) {
               o.removeEventListener(tmpArr[i].type, tmpArr[i].listener, cap);
            }
            for (var p:int = 0; p < tmpArr.length; p++) {
               objArr.splice(p);
            }

            if (tmpArr.length == 0) {
               delete objDict[o]
            }
         }else {
            trace("_______object has no listeners");
         }
      }
   }
}
1 голос
/ 15 февраля 2009

Что-то, что мне нравится делать, - это использовать динамический класс Global и добавить краткую ссылку на встроенную функцию слушателя Это предполагает, что вам нравится иметь функцию слушателя в методе addEventListener, как я. Таким образом, вы можете использовать removeEventListener внутри addEventListener :)

Попробуйте это:

package {

import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;

[SWF(width="750", height="400", backgroundColor="0xcdcdcd")]
public class TestProject extends Sprite
{   
    public function TestProject()
    {
        addEventListener(Event.ADDED_TO_STAGE, Global['addStageEvent'] = function():void {
            var i:uint = 0;
            //How about an eventlistener inside an eventListener?
            addEventListener(Event.ENTER_FRAME, Global['someEvent'] = function():void {
                //Let's make some text fields
                var t:TextField = new TextField();
                    t.text = String(i);
                    t.x = stage.stageWidth*Math.random();
                    t.y = stage.stageHeight*Math.random();
                addChild(t);
                i++;
                trace(i);
                //How many text fields to we want?
                if(i >= 50) {
                    //Time to stop making textFields
                    removeEventListener(Event.ENTER_FRAME, Global['someEvent']);
                    //make sure we don't have any event listeners
                    trace("hasEventListener(Event.ENTER_FRAME) = "+hasEventListener(Event.ENTER_FRAME));    
                }
            });

            //Get rid of the listener
            removeEventListener(Event.ADDED_TO_STAGE, Global['addStageEvent']);
            trace('hasEventListener(Event.ADDED_TO_STAGE) = '+hasEventListener(Event.ADDED_TO_STAGE));

        });
    }

}   

}

// смотри сюда! Это важный бит динамический класс Global {}

Секрет в динамическом классе Global. При этом вы можете динамически добавлять свойства во время выполнения.

0 голосов
/ 18 августа 2011
0 голосов
/ 04 октября 2010

Следующее не решает фундаментальную проблему удаления неизвестных слушателей событий, но если вам нужно отключить все связанные с мышью события, включая неизвестные, просто используйте: mouseEnabled = false для цели вашего события.

Больше хороших вещей здесь: http://www.thoughtprocessinteractive.com/blog/the-power-and-genius-of-mousechildren-and-mouseenabled

0 голосов
/ 28 сентября 2010
private function callFunction(function:Function):void
{
     checkObject();
     obj.addEventListener(MouseEvent.CLICK,function);
}

private function checkObject():void
{
    if(obj.hasEventListener(MouseEvent.CLICK))
   {
      //here remove that objects
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...