Вспышка событий при наведении мыши - PullRequest
3 голосов
/ 31 августа 2011

Есть ли способ узнать, какие методы вызываются при наведении мыши на объект в проекте Flash?

Ответы [ 6 ]

5 голосов
/ 03 сентября 2011

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

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

Надеюсь, это поможет.

(просто чтобы убедиться, что для этого вам понадобится Debug Player)

4 голосов
/ 31 августа 2011

Нет, это невозможно, если вы не переопределите addEventListener и не отследите добавленных слушателей самостоятельно.

Единственный похожий метод, предоставленный нативным EventDispatcher , - это hasEventListener, которыйпозволяют только проверить, есть ли зарегистрированный прослушиватель для данного типа события.

3 голосов
/ 05 сентября 2011

Пока что частичное решение @ rvmook является наиболее близким с моей точки зрения.Было бы полезно, если вы используете метод DisplayObjectContainer getObjectsUnderPoint () , чтобы получить список экранных объектов, которые вы переворачиваете, затем циклически просматриваете их и проверяете, какие из них имеют обработчики событий при опрокидывании / наведении курсора мыши, а затем продолжите детализацию.

Таким образом, одним из коротких решений будет:

  1. Загрузите SWF-файл, который вы хотите узнать, имя этого обработчика ролловера / наведения мыши. *
  2. Добавьте обработчик ролловера(с пузырьками, установленными в true)
  3. В обработчике при опрокидывании переберите объекты под мышью, которые имеют обработчики при опрокидывании / наведении курсора, и получите их детали.

Примечание! getObjectsUnderPoint () работает, если загрузочный SWF-файл имеет разрешения от домена, в котором размещен загруженный SWF-файл.Один из способов найти - метод InIncesscessObjectsUnderPoint () .Если у вас есть загруженный SWF-файл, проблем не должно быть.В противном случае вам потребуется либо файл crossdomain.xml в домене, где размещен загруженный SWF-файл, предоставляющий доступ к домену SWF-файла загрузчика (и SWF-файл загрузчика должен передать new LoaderContext(true) в качестве второго параметра для метода load () объекта Loader), либо использовать сторону сервера.скрипт на выбранном вами языке для прокси / копирования сначала загруженного SWF-файла.

Вот базовый пример того, что я имею в виду:

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

Это следует делать, если вам нужно только найтииз названия метода.Если вам нужна дополнительная информация, вы можете получить доступ к байт-массиву загруженного SWF-файла и проанализировать байт-код actionscript, чтобы получить информацию.Я должен признать, что двоичные файлы и ассемблер немного недоступны, но, к счастью, есть отличные библиотеки для декомпиляции SWF-файлов во время выполнения в as3. AS3SWF блестящий, но не имеет большого значения для тегов ActionScript, в то время как as3commons - это большая коллекция библиотек, специализирующихся на аспектах кода.

Вотадаптация предыдущего примера, которая использует библиотеки as3-commons ( байт-код , lang , logging и отражает ) для отображения методаподпись и тело (как инструкции AVM2):

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

    }
}

Для целей документирования вот код загруженного SWF-файла:

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

, а вот пример детальной трассировки метода с использованиемgetMethodDetails в моем примере AdvancedInfo:

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)

Для получения дополнительной информации о инструкциях AVM2 см. документацию или спецификации формата SWF-файла (ссылка в формате PDF).

Другие варианты, включающие стороннее программное обеспечение, которое я не полностью изучил, были бы:

  1. Использование FlashFirebug - Лично мне не удалось запустить егоможет я ненастроить правильно.
  2. Используйте getObjectsUnderPoint для трассировки информации об объектах (имя экземпляра / и т. д.) с помощью обработчиков ролловера / наведения мыши, а затем используйте коммерческий декомпилятор для поиска обработчика с использованием полученной информации.

НТН

2 голосов
/ 02 сентября 2011

Насколько велик исходный код? Возможно, вам удастся выполнить поиск проекта для "addEventListener (MouseEvent". Установите точки останова на ссылку на функцию для каждого экземпляра, который вы можете, и посмотрите, какой из них запускает нужное поведение. работать, чем вы надеетесь, но это идея.

Обратите внимание, что есть и другие способы, с помощью которых приложение может вызывать поведение, похожее на мышь. Например, экземпляры MovieClip имеют свойство mouseX и mouseY, которое кто-то может отслеживать на слушателе Event.ENTER_FRAME, чтобы также вызвать визуальное изменение. Возможно, вам также потребуется проверить это поведение.

2 голосов
/ 31 августа 2011

Может быть, это поможет вам узнать поток событий в AS3: http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7e4f.html

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

Я не могу думать ни о чем другом.

1 голос
/ 03 сентября 2011
  1. В вашем коде используйте трассировку («это было вызвано») в функциях, которые вы хотите отслеживать при вызове
  2. Установить версии Flash отладчика http://www.adobe.com/support/flashplayer/downloads.html
  3. Вы можете отслеживать следы во время выполнения с http://code.google.com/p/flash-tracer/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...