有什么方法可以找出在Flash项目中的对象上移动鼠标时调用哪些方法?
答案 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()方法获取滚动的显示对象列表,然后遍历它们并检查哪个具有翻转/鼠标悬停事件处理程序,然后继续向下钻取,则会有所帮助。
所以一个简短的解决方案是:
注意! 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库(bytecode,lang,logging和reflect)的前一个示例的修改,以显示方法签名和正文(作为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说明的详细信息,请访问documentation或SWF File format specs(PDF链接)。
涉及第三方软件的其他选项我还没有完全探索过:
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)