【问题标题】:Simulating mouse events in Actionscript 3在 Actionscript 3 中模拟鼠标事件
【发布时间】:2012-09-22 20:27:27
【问题描述】:

给定舞台坐标 (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));

这是唯一的选择吗?

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

我正在使用 FlashDevelop 编写代码,如果这有什么不同的话。

【问题讨论】:

  • getObjectsUnderPoint() 只返回第一个 InteractiveObject,然后只返回形状。这要么是文档中的遗漏,要么是一个错误。

标签: actionscript dispatchevent


【解决方案1】:

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

编辑:正如 cmets 中所指出的,鼠标事件必须在 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

【讨论】:

  • 感谢您的回复。在进一步调查之后,似乎我的 e.stageX 问题只发生在目标是位图而不是 Sprite 时(可能是因为位图不是 InteractiveObject 的子类?)。我将尝试按照您的示例进行操作,但如果目标不是一个,我会爬上去寻找一个 InteractiveObject。
  • 是的,这似乎是问题所在,非交互式对象不可点击。弹出列表,搜索 InteractiveObject 实例似乎可以解决问题。我已经更新了代码示例。
【解决方案2】:

对于问题 1:创建 MouseEvent(为其分配本地 x,y)后,您应该能够直接引用 e.stageX 并将其设置为您想要的,然后再调度事件。它只是 MouseEvent 实例的一个属性。 对于#2,currentTarget 始终是鼠标下方最上面的东西,而 target 是正在分派事件的东西——假设事件确实是由鼠标交互分派的。在您的情况下,您可以将目标设置为您调度事件的任何对象,并任意设置 currentTarget。真正的问题是,这是否是目前处理鼠标下方内容的最有效方法?答案是,可能不是。您最好使用 MOUSE_OVER 事件来密切关注鼠标现在所在的位置,将其存储为变量,以便在您想要调用它时使用,并且不要尝试迭代整个显示链一直如此(因为 Flash 本身比您在循环中执行的速度要快得多)。如果您将 mouseOver 放在舞台上,然后只检查 currentTarget,那么您将在每一帧更改鼠标下的最上面的项目。

你应该知道(为了防止一些明显的讨厌的脚本),某些动作不能被动作脚本动态生成的鼠标事件触发。其中包括打开文件引用和全屏显示。

【讨论】:

    【解决方案3】:

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

    实际上,在我的情况下,解决方案非常明显...... 全局坐标仅在事件发送后才填充,否则事件如何知道如何将局部坐标转换为全局坐标?

    这是另一个陷阱,除了不检查用于调度事件的对象是否为 InteractiveObject

    我发布这个是因为其他人可能会因为这两个陷阱而面临这个问题。一个简单易读的快速答案。

    【讨论】:

      猜你喜欢
      • 2010-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-08
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      相关资源
      最近更新 更多