在Actionscript 3中模拟鼠标事件

在Actionscript 3中模拟鼠标事件,actionscript,dispatchevent,Actionscript,Dispatchevent,给定阶段坐标(x,y),我想让我的flash应用程序的行为就像用户点击位置(x,y)一样。就是说, function simulateClick(x:Number, y:Number):void{ var e:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, false, x, y) stage.dispatchEvent(e); } 我找到了一大堆关于这类事情的网页,它们都给出了与上述类似的解决方案。但是,这并不等同于用户

给定阶段坐标(x,y),我想让我的flash应用程序的行为就像用户点击位置(x,y)一样。就是说,

function simulateClick(x:Number, y:Number):void{
    var e:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, false, x, y)
    stage.dispatchEvent(e);
}
我找到了一大堆关于这类事情的网页,它们都给出了与上述类似的解决方案。但是,这并不等同于用户单击(x,y)。有两个问题:

第一个是e.stageX和e.stageY都是0。我不能直接设置它们。文档中说,它们是在设置e.localX和e.localY时计算的,但在dispatchEvent之前设置e.localX时,以及在事件侦听器中都不会发生这种情况

我可以用以下内容重写所有事件侦听器:

var p:Point = e.target.localToGlobal(new Point(e.localX, e.localY));
这是唯一的选择吗

第二个问题是,我的事件侦听器是向stage的子级注册的,而不是stage本身。所以我需要找出调用dispatchEvent的目标。显然,Flash能够确定目标应该是什么,即哪个对象拥有位置(x,y)处可见的最高像素,因为它在用户实际单击时会这样做。有没有一种简单的方法来获取这些信息,或者我应该编写自己的递归函数来做同样的事情?目前我正在使用DisplayObjectContainer.getObjectsUnderPoint,但不太正确


如果有什么不同的话,我正在用FlashDevelop写作。

对于问题1:在创建MouseEvent(为其指定一个本地x,y)之后,您应该能够直接引用e.stageX,并在发送事件之前将其设置为您想要的值。它只是MouseEvent实例的一个属性。 对于#2,currentTarget始终是鼠标下最上面的对象,而target是调度事件的对象——假设事件确实是由鼠标交互调度的。在本例中,您可以将目标设置为调度事件的任何对象,并任意设置currentTarget。真正的问题是,这是否是处理现在鼠标下的东西最有效的方法;答案是,可能不是。最好使用鼠标悬停事件来记录鼠标悬停的内容,将其存储为一个变量,当您想调用此变量时,可以使用该变量,并且不要一直尝试迭代整个显示链(因为Flash本机的运行速度远远快于您在循环中的运行速度)。如果你把鼠标放在舞台上,只需检查currentTarget,你就会在每一个变化的帧上得到鼠标下最上面的项目


您应该知道(为了防止一些明显的恶意脚本),某些操作不能由actionscript动态生成的鼠标事件触发。其中包括打开文件引用并全屏显示。

e.stageX/Y
已为我正确填充。。。而且
getObjectsUnderPoint()
似乎工作正常。我假设传递给
simulateClick
的x/y值是全局坐标

编辑:正如注释中指出的,必须在InteractiveObject实例上调度鼠标事件。。。相应地修改了代码

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.InteractiveObject;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Point;

public function simulateClick(x:Number, y:Number):void
{
    var objects:Array = stage.getObjectsUnderPoint(new Point(x, y));

    var target:DisplayObject;
    while(target = objects.pop())
    {
        if(target is InteractiveObject)
        {
            break;
        }
    }

    if(target !== null)
    {
        var local:Point = target.globalToLocal(new Point(x, y));

        var e:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, false, local.x, local.y);
        target.dispatchEvent(e);
    }
}

public function addedToStage():void
{
    var parent:Sprite = new Sprite();
    stage.addChild(parent);

    var child:Sprite = new Sprite();
    child.name = 'child 1';
    child.graphics.beginFill(0xff0000, 1);
    child.graphics.drawRect(0, 0, 200, 200);
    child.graphics.endFill();

    var child2:Sprite = new Sprite();
    child2.name = 'child 2';
    child2.graphics.beginFill(0xff00ff, 1);
    child2.graphics.drawRect(0, 0, 100, 100);
    child2.graphics.endFill();
    child2.x = 150;
    child2.y = 150;

    var bmpData:BitmapData = new BitmapData(80, 80, false, 0x00ff00);
    var bmp:Bitmap = new Bitmap(bmpData);
    bmp.name = 'bitmap';

    child2.addChild(bmp);

    parent.addChild(child);
    parent.addChild(child2);

    child2.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void
    {
        trace('target: ' + e.target.name);
        trace('localX: ' + e.localX);
        trace('localY: ' + e.localY);
        trace('stageX: ' + e.stageX);
        trace('stageY: ' + e.stageY);
    });

    simulateClick(190, 190);
}
输出:

target: child 2
localX: 40
localY: 40
stageX: 190
stageY: 190

我也面临过这个问题,让我有点头疼。 在我的情况下,我正在创建事件,执行一些复杂的计算,但是我无法检索全局坐标,即使我已经设置了局部坐标

事实上,在我的情况下,解决办法是显而易见的。。。 只有在调度事件后才会填充全局坐标,否则事件如何知道如何将本地坐标转换为全局坐标

这是另一个陷阱,没有检查用于分派事件的对象是否为InteractiveObject


我发布这篇文章是因为由于这两个陷阱,其他人可能会面临这个问题。简单易读的快速回答。

感谢您的回复。在进一步调查之后,似乎我的e.stageX问题只发生在目标是位图而不是精灵时(可能是因为位图不是InteractiveObject的子类?)。我将尝试按照您的示例进行操作,但如果目标不是交互式对象,则向上搜索交互式对象。是的,这似乎是问题所在,非交互式对象不可单击。在列表中弹出,搜索InteractiveObject实例似乎就可以做到这一点。我已经更新了代码示例。getObjectsUnderPoint()只返回第一个InteractiveObject,然后只返回形状。这要么是文档中的遗漏,要么是一个bug。