2008-10-08 4 views
6

Je veux avoir un bouton réutilisable qui peut être enregistré pour l'un des nombreux callbacks différents, déterminés par une source externe. Lorsqu'un nouveau rappel est défini, je veux supprimer l'ancien. Je veux également être en mesure d'effacer le rappel externe à tout moment.Existe-t-il un moyen de supprimer les écouteurs d'événements inconnus des objets?

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

J'ai vu des suggestions sur ici pour utiliser « arguments.callee » dans le rappel, mais je ne veux pas avoir cette fonctionnalité liée à la fonction de rappel - par exemple, je pourrais veux être en mesure de cliquez deux fois sur le bouton.

Suggestions?

Répondre

8

Je présume que vous ne voulez qu'une seule fonction de rappel à un moment donné. Si c'est Teh cas, alors pourquoi ne pas avoir une seule fonction de rappel associée à l'événement, cliquez sur le bouton qui s'appelle une fonction et avoir cette fonction soit réglable ...

<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 consommateur de votre contrôle qui abrite le bouton définirait onClickFunction avec la fonction appropriée. En fait, vous pouvez le régler aussi souvent que vous le souhaitez.

Si vous vouliez aller plus loin, vous pourriez sous-classer la classe AS3 Button et envelopper tout cela à l'intérieur.

+0

Gotcha. Vous savez, je pense que j'ai commencé à le faire et j'ai décidé de ne pas le faire pour une raison que je ne me souviens pas. De toute façon, votre présomption est correcte et c'est un bon moyen de faire ce que j'ai prévu. Merci. –

+0

Super, je suis content d'avoir pu aider. Si vous marquez ceci comme réponse, j'obtiendrai aussi quelques points de rep :-) – Simon

3

Stockez l'écouteur comme accessoire. Lorsqu'un autre événement est ajouté, vérifiez si l'écouteur existe et, si c'est le cas, appelez removeEventListener.

Vous pouvez également remplacer la méthode addEventListener de votre bouton. Lorsque addEventListener est appelé, stockez la fermeture avant de l'ajouter à l'événement dans un objet Dictionary. Lorsque addEventListener est appelé à nouveau, retirez-le:


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

Aucune de ces options ne fait ce que la question demande, à savoir récupérer un écouteur d'événement UNKOWN à partir d'un objet EventDispatcher existant. Ces méthodes stockent simplement un écouteur KNOWN avant qu'il ne soit ajouté à l'objet. Si l'écouteur n'est pas connu et stocké avant d'être ajouté à l'objet, il n'y a aucun moyen de le récupérer plus tard. – Triynko

+3

Mais ils offrent des moyens de faire connaître les auditeurs d'événements inconnus, ce qui est une autre façon d'aborder le problème. – voidstate

1

Quelque chose que je veux faire est d'utiliser une classe mondiale dynamique et ajouter une référence rapide à la ligne de fonction d'écouteur. C'est supposer que vous aimez avoir la fonction d'écouteur dans la méthode addEventListener comme je le fais. De cette façon, vous pouvez utiliser removeEventListener dans la addEventListener :)

Essayez ceci:

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

     }); 
    } 

} 

}

// looky ici! C'est le bit important dynamic class Global {}

Le secret est la classe dynamique Global. Avec cela, vous pouvez ajouter des propriétés dynamiquement à l'exécution.

4

Non. Vous devez conserver une référence à l'écouteur pour l'enlever. À moins que vous ne stockiez à l'avance une référence à la fonction d'écouteur, aucune méthode publique documentée n'est disponible pour extraire une telle référence d'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 

Comme vous pouvez le voir, il y a deux méthodes pour vous dire si un type d'événement a un écouteur ou un de ses parents a un écouteur, mais aucune de ces méthodes renvoient en fait une liste des auditeurs inscrits .

Maintenant, allez harceler Adobe pour avoir écrit une API aussi inutile.Fondamentalement, ils vous donnent la possibilité de savoir "si" le flux d'événements a changé, mais ils ne vous donnent aucun moyen de faire quoi que ce soit avec cette information!

2

J'ai écrit une sous-classe appelée EventCurb à cet effet, voir mon blog ici ou coller ci-dessous.

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