1

我正在做一个 AS3 项目,我正在努力解决一个特别脆弱的部分,在不久的将来需要大量重构。仅仅对单独的类进行单独的单元测试并不能捕捉到我们遇到的所有问题。例如,我们可能忘记在透明覆盖层上禁用鼠标事件,从而阻止对按钮的所有点击。因此,我正在尝试编写一个模拟真实用户输入的测试。

我试图在正确的位置手动将 MouseEvent 发送到舞台:

stage.dispatchEvent(new MouseEvent(MouseEvent.CLICK, true, true, 380, 490, stage));

由于舞台没有点击事件处理程序,我希望事件通过层次结构传播到实际处理它的按钮(就像我物理单击鼠标时一样)。然而,事实并非如此。

我知道我可以只在按钮上分派事件,但这不会检测到对象是否以某种方式受到阻碍。是否有某种方法可以模拟鼠标事件,以便它们正确地通过层次结构传播?

编辑: 我设法通过重新实现 Flash 的传播行为来做到这一点:

编辑 2: 如果有一个带有点击处理程序的部分透明覆盖,我以前的解决方案不起作用,比如其中有几个形状的 Sprite。问题是 hitTestPoint 方法返回 true,即使有问题的对象在那时是完全透明的。因此,我对其进行了修改以检查实际像素值:

private function clickObject(obj:DisplayObject) : void 
{
    var relPos:Point = new Point(obj.width / 2, obj.height / 2);
    var globalPos:Point = obj.localToGlobal(relPos);

    simulateClick(obj.stage, globalPos);
}

private function simulateClick(obj:InteractiveObject, globalPos:Point) : Boolean 
{
    // first, check if we have any children that would rather handle the event
    var container:DisplayObjectContainer = obj as DisplayObjectContainer;
    if (container != null) 
    {
        if (container.mouseChildren)
        {
            for (var i:int = 0; i < container.numChildren; ++i) 
            {
                var child:DisplayObject = container.getChildAt(i);
                var interactive:InteractiveObject = child as InteractiveObject;
                if (interactive != null) 
                {
                    if (simulateClick(interactive, globalPos)) 
                    {
                        // if we have found a handler in the children, we are done
                        return true;
                    }
                }
            }
        }
    }

    if (!obj.mouseEnabled) {
        return false;
    }

    if (obj.hitTestPoint(globalPos.x, globalPos.y)) 
    {
        var localPos:Point = obj.globalToLocal(globalPos);

        // check if object is visible at the clicked location
        var pixel:BitmapData = new BitmapData(1, 1);
        pixel.draw(obj, new Matrix(1, 0, 0, 1, -localPos.x, -localPos.y));
        var color:uint = pixel.getPixel32(0, 0);
        if ((pixel.getPixel32(0, 0) & 0xff000000) != 0)
        {
            // if yes, dispatch the click event
            var e:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, true, localPos.x, localPos.y, obj);
            obj.dispatchEvent(e);
            return true;
        }
    }

    return false;
}

不幸的是,至少还有一种情况没有涉及:如果对象是另一个对象的掩码。我不知道如何检查这一点,因为它可能是显示层次结构中的任何地方的掩码。我将不得不遍历整个树并检查每个显示对象以找出这一点。

所以,我的问题仍然存在:没有更简单的方法吗?

4

2 回答 2

2

我也遇到了 AS3 中的事件问题。我发现最好的方法是将 eventListeners 添加到调度事件的同一个对象中。在您的情况下,将 .addEventListener 添加到舞台并将函数作为子剪辑上的函数发送。例如:

    stage.addEventListener(MouseEvent.CLICK, object.object.clicked);

我希望这可能会有所帮助。我过去曾成功地使用过这种方法。

于 2012-12-11T16:53:54.607 回答
1

您可以使用stage.getObjectsUnderPoint(new Point(pointerX , pointerY )); 函数,它将返回带有对象的 You 数组。比删除覆盖对象和数组中的最后一个实例应该是最深的 DisplayObject。

注意:最后一个实例可以是图形或类似的东西,所以你应该遍历父对象以找到最近的 InteractiveObject。另外,不要忘记父对象可以有mouseChildren = falsemouseEnabled = false

于 2012-12-11T12:49:49.040 回答