鼠标悬停的Flash事件

时间:2011-08-31 14:45:56

标签: flash actionscript-3 actionscript

有什么方法可以找出在Flash项目中的对象上移动鼠标时调用哪些方法?

6 个答案:

答案 0 :(得分:5)

如果您尝试以下操作,您将能够跟踪对象上的每个侦听器。它将调用所有侦听器,而不会产生任何会引发错误的参数。如果您发现错误,可以解析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());
            }
        }
    }
}

希望这有帮助。

(只是为了确保,你需要一个调试播放器)

答案 1 :(得分:4)

不,除非您覆盖addEventListener并自行跟踪添加的侦听器,否则无法实现。

本机EventDispatcher提供的唯一类似方法是hasEventListener,它只允许您检查是否存在针对给定事件类型的已注册侦听器。

答案 2 :(得分:3)

到目前为止,@ rvmook的部分解决方案离我的观点最近。如果您使用DisplayObjectContainer的getObjectsUnderPoint()方法获取滚动的显示对象列表,然后遍历它们并检查哪个具有翻转/鼠标悬停事件处理程序,然后继续向下钻取,则会有所帮助。

所以一个简短的解决方案是:

  1. 加载要查找翻转/鼠标悬停处理程序名称的swf。*
  2. 添加翻转处理程序(将气泡设置为true)
  3. 在翻转处理程序中循环浏览具有翻转/鼠标悬停处理程序的鼠标下的对象并获取其详细信息。
  4. 注意! getObjectsUnderPoint()如果加载swf具有来自托管加载的swf的域的权限,则有效。查找areInaccessibleObjectsUnderPoint()方法的一种方法。如果你拥有加载的swf,应该没有任何问题。否则,您需要在托管加载的swf的域上使用crossdomain.xml,授予加载器swf的域访问权限(并且加载器swf应该传递new LoaderContext(true)作为Loader intance的load()方法的第二个参数)或者使用服务器端脚本,您选择的语言首先代理/复制加载的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的bytearray并解析actionscript字节码以获取信息。我必须承认二进制和汇编有点超出我的范围,但幸运的是有一些很棒的库在运行时在as3中反编译swf文件。 AS3SWF是一个很棒的,但不会对actionscript标签做太多的处理,而as3commons是一个很好的库集合,专门研究代码方面。

    以下是使用as3-commons库(bytecodelangloggingreflect)的前一个示例的修改,以显示方法签名和正文(作为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;
            }
        }
    }
    

    以下是使用AdvancedInfo示例中的getMethodDetails的方法详细信息跟踪示例:

    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说明的详细信息,请访问documentationSWF File format specs(PDF链接)。

    涉及第三方软件的其他选项我还没有完全探索过:

    1. 使用FlashFirebug - 我个人没有设法得到它 跑步,也许我没有正确设置。
    2. 使用getObjectsUnderPoint通过翻转/鼠标悬停处理程序跟踪对象(实例名称等)的信息,然后使用商业反编译器使用获得的信息查找处理程序。
    3. HTH

答案 3 :(得分:2)

也许它可以帮助您了解AS3中的事件流程:http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7e4f.html

简而言之,有两个阶段,捕捉和冒泡。当事件从显示堆栈的底部移动到顶部时,您对冒泡阶段感兴趣。在此阶段,各种对象在行进和执行各种事件侦听器(您感兴趣的方法)时捕获事件。如果您可以访问这些对象的源代码,则可以在这些方法中插入调试消息。

我想不出别的什么。

答案 4 :(得分:2)

源代码有多大?您可以通过执行“addEventListener(MouseEvent”)的项目搜索来逃避。在每个实例的函数引用上放置断点,并查看哪一个正在为您正在寻找的行为触发。可能还有一点工作比你希望的,但这是一个想法。

注意,应用程序可以通过其他方式触发类似鼠标的行为。例如,MovieClip实例具有mouseX和mouseY属性,有人可以监视Event.ENTER_FRAME侦听器以触发视觉更改。您可能还需要检查该行为。

答案 5 :(得分:1)

  1. 在您的代码中,如果调用
  2. ,则在要监视的函数中使用trace(“this that called”)
  3. 安装Flash调试器版本http://www.adobe.com/support/flashplayer/downloads.html
  4. 您可以使用http://code.google.com/p/flash-tracer/
  5. 在运行时监控跟踪