3 Stimmen

Flash-Ereignisse bei Mouse-Over

Gibt es eine Möglichkeit, herauszufinden, welche Methoden aufgerufen werden, wenn man die Maus über ein Objekt in einem Flash-Projekt bewegt?

5voto

Rick van Mook Punkte 2055

Wenn Sie das Folgende ausprobieren, können Sie jeden Hörer Ihres Objekts aufspüren. Es werden alle Listener ohne Argumente aufgerufen, was einen Fehler auslöst. Wenn Sie den Fehler abfangen, können Sie error.getStackTrace um die Standorte der Hörer zu sehen.

var members:Object = getMemberNames(yourObject);

for each (var name:QName in members) 
{
    if (name.localName == "listeners") 
    {
        for (var i : int = 0; i < yourObject[name].length; i++) 
        {
            var func:Function = yourObject[name][i];

            try
            {
                func.call();
            }
            catch(error:Error)
            {
                trace(error.getStackTrace());
            }
        }
    }
}

Ich hoffe, das hilft.

(nur um sicher zu gehen, benötigen Sie einen Debug Player dafür)

4voto

bummzack Punkte 5881

Nein, das ist nicht möglich, es sei denn, Sie überschreiben die addEventListener und behalten Sie selbst den Überblick über die hinzugefügten Hörer.

Die einzige ähnliche Methode, die von der nativen EventDispatcher es hasEventListener die es Ihnen nur ermöglichen würde, zu überprüfen, ob es einen registrierten Listener für einen bestimmten Ereignistyp gibt oder nicht.

3voto

George Profenza Punkte 47681

Bislang ist die Teillösung von @rvmook aus meiner Sicht die beste. Es würde helfen, wenn Sie DisplayObjectContainer's getObjectsUnderPoint() Methode, um eine Liste von Anzeigeobjekten zu erhalten, über die Sie rollen, dann in einer Schleife prüfen, welches Objekt Rollover/Mouseover-Ereignishandler hat, und dann weiter nach unten bohren.

Eine kurze Lösung wäre also:

  1. Laden Sie die gewünschte swf-Datei, um den Namen des Rollover/Mouseover-Handlers herauszufinden.*
  2. Fügen Sie einen Rollover-Handler hinzu (mit Blasen auf true gesetzt)
  3. In der Rollover-Handler-Schleife durch die Objekte unter der Maus, die Rollover/Mouseover-Handler haben und erhalten ihre Details.

Achtung! getObjectsUnderPoint() funktioniert, wenn die ladende swf über die Berechtigungen der Domäne verfügt, die die geladene swf hostet. Ein Weg zu finden areInaccessibleObjectsUnderPoint() Methode. Wenn Sie die geladene swf besitzen, sollte es keine Probleme geben. Andernfalls benötigen Sie entweder eine crossdomain.xml auf der Domäne, die die geladene swf beherbergt, die der Domäne der geladenen swf Zugriff gewährt (und die geladene swf sollte die new LoaderContext(true) als zweiten Parameter für die load()-Methode der Loader-Intanz) oder verwenden Sie ein serverseitiges Skript in der Sprache Ihrer Wahl, um die geladene swf zuerst zu projizieren/zu kopieren.

Hier ist ein einfaches Beispiel dafür, was ich meine:

package{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.Point;
    import flash.net.URLRequest;
    import flash.sampler.getMemberNames;

    public class BasicInfoTest extends Sprite{

        private var cursor:Point = new Point();

        public function BasicInfoTest(){
            init();
        }
        private function init():void{
            var loader:Loader = addChild(new Loader) as Loader;
            loader.load(new URLRequest('B.swf'));
            addEventListener(MouseEvent.ROLL_OVER,onOver);
        }
        private function onOver(event:MouseEvent):void{
            cursor.x = mouseX;cursor.y = mouseY;
            var obj:Array = getObjectsUnderPoint(cursor);
            var numObj:int = obj.length; 
            for(var i:int = 0 ; i < numObj ; i++){//look for objects under cursor that have rollover/mouseover event handlers
                if(obj[i].hasEventListener(MouseEvent.ROLL_OVER) || obj[i].hasEventListener(MouseEvent.MOUSE_OVER)){
                    var members:Object = getMemberNames(obj[i]);//use @rvmook's method to get listeners
                    for each (var name:QName in members){
                        if (name.localName == "listeners"){
                            for (var j : int = 0; j < obj[i][name].length; j++){
                                var func:Function = obj[i][name][j];
                                try{
                                    func.call();
                                }catch(error:Error){
                                    trace('Methods called on mouse over:',error.message.split('on ')[1].split('.')[0]);//parse error message, you might need to adapt this
                                    trace('StackTrace',error.getStackTrace()); 
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Das sollte genügen, wenn Sie nur den Namen der Methode herausfinden wollen. Wenn Sie weitere Informationen benötigen, können Sie auf das Bytearray der geladenen SWF zugreifen und den Actionscript-Bytecode parsen, um Informationen zu erhalten. Ich muss zugeben, dass Binär- und Assembler-Code etwas außerhalb meiner Reichweite liegen, aber zum Glück gibt es einige großartige Bibliotheken, um swf-Dateien zur Laufzeit in as3 zu dekompilieren. AS3SWF ist brillant, hat aber nicht viel mit Actionscript-Tags zu tun, während as3commons ist eine großartige Sammlung von Bibliotheken, die auf den Code-Aspekt spezialisiert sind.

Hier ist eine Anpassung des vorherigen Beispiels, die die as3-commons-Bibliotheken verwendet( Bytecode , lang , Protokollierung y reflektieren ), um die Signatur und den Rumpf der Methode (als AVM2-Anweisungen) anzuzeigen:

package{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.Point;
    import flash.net.*;
    import flash.sampler.getMemberNames;
    import flash.utils.ByteArray;

    import org.as3commons.bytecode.swf.SWFFile;
    import org.as3commons.bytecode.swf.SWFFileIO;
    import org.as3commons.bytecode.tags.DoABCTag;

    public class AdvancedInfo extends Sprite{

        private var cursor:Point = new Point();
        private var methodInfo:Array;

        public function AdvancedInfo(){
            init();
        }
        private function init():void{
            var byteLoader:URLLoader = new URLLoader(new URLRequest('B.swf'));
            byteLoader.dataFormat = URLLoaderDataFormat.BINARY;
            byteLoader.addEventListener(Event.COMPLETE,bytesLoaded);
        }
        private function bytesLoaded(event:Event):void{
            var ba:ByteArray = event.target.data as ByteArray;//get swf bytes
            var swfFile:SWFFile = new SWFFileIO().read(ba);//read the bytes using as3-commons
            var abcTags:Array = swfFile.getTagsByType(DoABCTag);//get actionscript bytecode (ABC) tags
            for each(var tag:DoABCTag in abcTags) methodInfo = tag.abcFile.methodInfo;//loop though tags and get method information
            //display and rollOver
            var d:Loader = addChild(new Loader()) as Loader;
            d.loadBytes(ba);
            addEventListener(MouseEvent.ROLL_OVER, rolledOver,true,0,true);
        }
        private function getMethodDetails(methodName:String):String{
            var result:String = '';
            for(var i:int = 0 ; i < methodInfo.length; i++){
                if(methodInfo[i].methodName == methodName){
                    result += 'signature:\t'+methodInfo[i]+'\n';
                    result += 'body:\t'+methodInfo[i].methodBody;
                    return result;
                }
              }
            return result;
        }
        private function rolledOver(event:MouseEvent):void{
            cursor.x = mouseX;cursor.y = mouseY;
            var obj:Array = getObjectsUnderPoint(cursor);
            var numObj:int = obj.length; 
            for(var i:int = 0 ; i < numObj ; i++){
                if(obj[i].hasEventListener(MouseEvent.ROLL_OVER) || obj[i].hasEventListener(MouseEvent.MOUSE_OVER)){
                    var members:Object = getMemberNames(obj[i]);
                    for each (var name:QName in members){
                        if (name.localName == "listeners"){
                            for (var j : int = 0; j < obj[i][name].length; j++){
                                var func:Function = obj[i][name][j];
                                try{
                                    func.call();
                                }catch(error:Error){
                                    var methodName:String = error.message.split('on ')[1].split('.')[0].split('/')[1].split('()')[0]; 
                                    trace(getMethodDetails(methodName));
                                }
                            }
                        }
                    }
                }
            }
        }

    }
}

Zu Dokumentationszwecken finden Sie hier den Code der geladenen SWF-Datei:

package {
    import flash.events.*;
    import flash.display.*;

    public class B extends Sprite {
        public function B() {
            addEventListener(Event.ADDED_TO_STAGE, init)
        }
        private function init(event:Event = null) : void {
            for (var i : int = 0; i < 1000 ; i++) {
                var b:Sprite = addChild(new Sprite()) as Sprite;
                b.graphics.lineStyle(Math.random()*3);
                b.graphics.drawCircle(-3, -3, 3);
                b.x = 3+Math.random() * stage.stageWidth - 6;
                b.y = 3+Math.random() * stage.stageHeight - 6;
                b.buttonMode = true;
                b.addEventListener(MouseEvent.ROLL_OVER, onRollOver);
            }
        }
        private function onRollOver(event : MouseEvent) : void {
            event.currentTarget.scaleX = event.currentTarget.scaleY = .1 + Math.random() * 2.1;
        }
    }
}

und hier ist ein Beispiel für die Verfolgung von Methodendetails unter Verwendung von getMethodDetails in meinem AdvancedInfo-Beispiel:

signature:  private function QName[Namespace[private::B]:onRollOver](QName[Namespace[public::flash.events]:MouseEvent]) : QName[Namespace[public]:void]
body:   
    private function QName[Namespace[private::B]:onRollOver](QName[Namespace[public::flash.events]:MouseEvent]) : QName[Namespace[public]:void]
    {   
        //maxStack=5, localCount=3, initScopeDepth=9, maxScopeDepth=10
        0:debugfile     [/Users/george/Documents/Flex Builder 3/Del/src;;B.as]:2
        2:debugline     [28]:4
        4:getlocal_0        :5
        5:pushscope     :6
        6:debug     [1, 18, 0, 28]:11
        11:debugline        [29]:13
        13:getlocal_1       :14
        14:getproperty      [QName[Namespace[public]:currentTarget]]:16
        16:getlocal_1       :17
        17:getproperty      [QName[Namespace[public]:currentTarget]]:19
        19:pushdouble       [0.1]:21
        21:getlex       [QName[Namespace[public]:Math]]:23
        23:callproperty     [QName[Namespace[public]:random], 0]:26
        26:pushdouble       [2.1]:28
        28:multiply     :29
        29:add      :30
        30:dup      :31
        31:setlocal_2       :32
        32:setproperty      [Multiname[name=scaleY, nsset=[Namespace[private::B], Namespace[public], Namespace[private::B.as$25], Namespace[packageInternalNamespace], Namespace[namespace::http://adobe.com/AS3/2006/builtin], Namespace[protectedNamespace::B], Namespace[staticProtectedNamespace::B], Namespace[staticProtectedNamespace::flash.display:Sprite], Namespace[staticProtectedNamespace::flash.display:DisplayObjectContainer], Namespace[staticProtectedNamespace::flash.display:InteractiveObject], Namespace[staticProtectedNamespace::flash.display:DisplayObject], Namespace[staticProtectedNamespace::flash.events:EventDispatcher], Namespace[staticProtectedNamespace::Object]]]]:34
        34:getlocal_2       :35
        35:kill     [2]:37
        37:setproperty      [Multiname[name=scaleX, nsset=[Namespace[private::B], Namespace[public], Namespace[private::B.as$25], Namespace[packageInternalNamespace], Namespace[namespace::http://adobe.com/AS3/2006/builtin], Namespace[protectedNamespace::B], Namespace[staticProtectedNamespace::B], Namespace[staticProtectedNamespace::flash.display:Sprite], Namespace[staticProtectedNamespace::flash.display:DisplayObjectContainer], Namespace[staticProtectedNamespace::flash.display:InteractiveObject], Namespace[staticProtectedNamespace::flash.display:DisplayObject], Namespace[staticProtectedNamespace::flash.events:EventDispatcher], Namespace[staticProtectedNamespace::Object]]]]:39
        39:debugline        [30]:41
        41:returnvoid       :42
    }
traits=(no traits)

Weitere Informationen zu den AVM2-Anweisungen finden Sie auf der Website Dokumentation oder die SWF-Dateiformat-Spezifikationen (PDF-Link).

Andere Optionen, die Software von Drittanbietern beinhalten und die ich noch nicht vollständig erforscht habe, wären:

  1. Verwendung von FlashFirebug - Ich persönlich habe es nicht geschafft, es zu bekommen. zum Laufen zu bringen, vielleicht habe ich es nicht richtig eingerichtet.
  2. Verwenden Sie getObjectsUnderPoint, um Informationen über Objekte (Instanznamen usw.) mit Rollover/Mouseover-Handlern zu ermitteln, und verwenden Sie dann einen kommerziellen Decompiler, um den Handler anhand der gewonnenen Informationen zu suchen.

HTH

2voto

Corneliu Dascălu Punkte 3720

Vielleicht würde es Ihnen helfen, den Ereignisablauf in AS3 zu kennen: http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7e4f.html

Kurz gesagt, es gibt zwei Phasen: Capturing und Bubbling. Sie interessieren sich für die Bubbling-Phase, in der das Ereignis von unten nach oben auf dem Anzeigestapel wandert. In dieser Phase fangen verschiedene Objekte das Ereignis auf seinem Weg ab und führen verschiedene Ereignis-Listener aus (die Methoden, an denen Sie interessiert sind). Wenn Sie Zugriff auf den Quellcode dieser Objekte haben, können Sie eine Debug-Meldung in diese Methoden einfügen.

Ich kann mir nichts anderes vorstellen.

2voto

meddlingwithfire Punkte 1437

Wie umfangreich ist der Quellcode? Möglicherweise reicht es aus, eine Projektsuche nach "addEventListener(MouseEvent" durchzuführen. Setzen Sie Haltepunkte auf die Funktionsreferenz für jede Instanz, die Sie finden können, und sehen Sie, welche für das gesuchte Verhalten ausgelöst wird. Wahrscheinlich ist das ein bisschen mehr Arbeit, als Sie sich erhoffen, aber es ist eine Idee.

Es gibt noch andere Möglichkeiten, wie eine Anwendung ein Mouse-over-ähnliches Verhalten auslösen kann. Zum Beispiel haben MovieClip-Instanzen eine mouseX- und mouseY-Eigenschaft, die jemand auf einem Event.ENTER_FRAME-Listener überwachen könnte, um ebenfalls eine visuelle Änderung auszulösen. Möglicherweise müssen Sie auch auf dieses Verhalten achten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X