2008-10-08 34 views
6

Quiero tener un botón reutilizable que se pueda registrar para una de muchas devoluciones de llamadas diferentes, determinado por una fuente externa. Cuando se establece una nueva devolución de llamada, quiero eliminar la anterior. También quiero poder borrar la devolución de llamada externamente en cualquier momento.¿Hay alguna manera de eliminar los detectores de eventos desconocidos de los objetos?

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 
    } 
} 

que he visto sugerencias sobre aquí para utilizar "arguments.callee" dentro de la devolución de llamada, pero no quiero tener esa funcionalidad ligada a la devolución de llamada - por ejemplo, puede ser que quiero ser capaz de haga clic en el botón dos veces.

Sugerencias?

Respuesta

8

Supongo que solo quiere una función de devolución de llamada en un momento dado. Si eso es teh caso, entonces por qué no tener una sola función de devolución de llamada asociada con el evento click en el botón que a su vez llama función y tienen esa función sea ajustable ...

<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 
    } 
} 

Un consumidor de su control que alberga el botón establecería la función onClickFunction con la función apropiada. De hecho, puedes configurarlo tantas veces como quieras.

Si quisiera dar un paso más, podría subclase la clase de botón AS3 y envolver todo esto dentro de ella.

+0

Gotcha. Sabes, creo que comencé a hacer eso y decidí no hacerlo por algún motivo que no recuerdo. De cualquier manera, su presunción es correcta y es una buena manera de hacer lo que me he propuesto. Gracias. –

+0

Genial, me alegro de poder ayudar. Si marca esto como la respuesta, obtendré algunos puntos de repetición también :-) – Simon

3

Almacene el oyente como un accesorio. Cuando se agrega otro evento, verifique si el oyente existe, y si lo hace, llame a removeEventListener.

Alternativamente, anule el método addEventListener de su botón. Cuando se invoca addEventListener, guarde el cierre antes de agregarlo al evento en un objeto Dictionary. Cuando addEventListener se llama de nuevo, y eliminar:


var listeners:Dictionary = new Dictionary();

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

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

}; 

+0

. Ninguna de esas opciones hace lo que la pregunta está haciendo, que es recuperar un detector de eventos UNKOWN de un objeto EventDispatcher existente. Estos métodos solo almacenan un detector CONOCIDO antes de que se agregue al objeto. Si el oyente no es conocido y almacenado antes de que se agregue al objeto, entonces no hay forma de recuperarlo más tarde. – Triynko

+3

Pero sí ofrecen formas de dar a conocer a los oyentes desconocidos, lo cual es otra forma de abordar el problema. – voidstate

1

Algo que me gusta hacer es utilizar una clase global dinámica y añadir una referencia rápida a la línea función de escucha. Esto supone que desea que la función del oyente funcione en el método addEventListener como yo. De esta manera, se puede utilizar dentro de la removeEventListener addEventListener :)

Trate de hacer esto:

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

     }); 
    } 

} 

}

// mire aquí! Este es el bit importante clase dinámica Global {}

El secreto es la clase dinámica Global. Con eso puedes agregar propiedades dinámicamente en tiempo de ejecución.

4

No. Necesita mantener una referencia al oyente para eliminarlo. A menos que almacene una referencia a la función del oyente por adelantado, no hay un método público documentado disponible para recuperar dicha referencia de un 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 

Como se puede ver, hay dos métodos para indicar si un tipo de evento tiene un detector registrado o uno de sus padres tiene un detector registrado, pero ninguno de esos métodos en realidad devolver una lista de oyentes registrados .

Ahora acceda a Adobe para escribir una API tan inútil.Básicamente, te dan la capacidad de saber "si" el flujo del evento ha cambiado, ¡pero no te permiten hacer nada con esa información!

2

Escribí una subclase llamada EventCurb para ese propósito, vea mi blog aquí o pegue a continuación.

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"); 
     } 
     } 
    } 
} 
0
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 
    } 
} 
Cuestiones relacionadas