【问题标题】:Flash events on mouse over鼠标悬停时的 Flash 事件
【发布时间】:2011-08-31 14:45:56
【问题描述】:

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

【问题讨论】:

  • 不确定你的意思。您想获取注册到对象的 ROLL_OVER 和 MOUSE_OVER 事件的所有侦听器的列表吗?
  • @shanethehat,基本上。当我将鼠标移到一个对象上时,会调用方法。我想看看,当它们被调用时,方法是什么。
  • @The_asMan,Flash Builder 4.5。
  • 您是否已经拥有对被鼠标悬停的特定对象的引用,或者您还需要找到它吗?
  • 你应该获取方法或侦听器或两者兼而有之?

标签: flash actionscript-3 actionscript


【解决方案1】:

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

希望这会有所帮助。

(为了确定,您需要一个调试播放器)

【讨论】:

    【解决方案2】:

    不,除非您覆盖 addEventListener 并自己跟踪添加的侦听器,否则这是不可能的。

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

    【讨论】:

    • 即使这不是标准 Flash 环境的一部分,也许有一个调试器可以提供帮助?
    • @Radu 您可以在调试器中看到所有附加的侦听器,例如 Flash Builder 附带的侦听器。但是,这些仅显示为“函数指针”,它不会告诉您确切的函数(除非您以某种方式解析该内存地址)。
    • 如何在 Flash Builder 调试器中查看所有附加的侦听器?
    • 您可以在调试器中浏览监听器数组。但它只包含Function 指针。老实说没多大用处。
    【解决方案3】:

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

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

    1. 加载您要查找该翻转/鼠标悬停处理程序名称的 swf。*
    2. 添加翻转处理程序(气泡设置为 true)
    3. 在翻转处理程序中循环遍历鼠标下具有翻转/鼠标悬停处理程序的对象并获取它们的详细信息。

    注意! getObjectsUnderPoint() 如果加载的 swf 具有来自托管加载的 swf 的域的权限,则可以工作。一种查找areInaccessibleObjectsUnderPoint() 方法的方法。如果您拥有已加载的 swf,则应该没有任何问题。否则,您要么需要托管已加载 swf 的域上的 crossdomain.xml,以授予加载程序 swf 的域访问权限(加载程序 swf 应传递 new LoaderContext(true) 作为 Loader 实例的 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 是一个很棒的库,但对动作脚本标签的处理不多,而 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 链接)。

    涉及我尚未完全探索的第 3 方软件的其他选项是:

    1. 使用FlashFirebug - 就我个人而言,我还没有设法得到它 正在运行,可能我没有正确设置。
    2. 使用 getObjectsUnderPoint 通过翻转/鼠标悬停处理程序跟踪有关对象(实例名称等)的信息,然后使用商业反编译器使用获得的信息查找处理程序。

    HTH

    【讨论】:

      【解决方案4】:

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

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

      我想不出别的了。

      【讨论】:

      • 就是这样,我确实可以访问源代码,但是发生了很多事情,我不知道所有被调用的方法是什么。我正在寻找一种方法来隔离这些方法并查看它们是哪些。
      【解决方案5】:

      源代码有多大?您可以通过执行项目搜索“addEventListener(MouseEvent”) 侥幸逃脱。为每个实例在函数引用上放置断点,然后查看哪个是针对您正在寻找的行为而触发的。可能多一点工作超出您的期望,但这是一个想法。

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

      【讨论】:

      • 太大了。我排除了所有可能的ENTER_FRAMEs。
      【解决方案6】:
      1. 在您的代码中,在您想要监控的函数中使用 trace("this was called")(如果被调用)
      2. 安装 Flash 调试器版本http://www.adobe.com/support/flashplayer/downloads.html
      3. 您可以在运行时使用http://code.google.com/p/flash-tracer/ 监控跟踪

      【讨论】:

      • 我很确定 OP 的意思是他正在寻找一种方法来查看哪些内部事件和方法被调用,而不是他自己的。
      猜你喜欢
      • 2016-08-08
      • 2018-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 2012-10-12
      • 1970-01-01
      相关资源
      最近更新 更多