我正在研究一个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;
}
不幸的是,至少有一个案例未被涵盖:如果该对象是另一个对象的掩码。我不知道如何检查这个,因为它可能是显示层次结构中任何位置的掩码。我将不得不遍历整个树并检查每个显示对象以找到它。
所以,我的问题仍然存在:是否有更简单的方法可以做到这一点?
答案 0 :(得分:1)
您可以使用 stage.getObjectsUnderPoint(新的Point(pointerX,pointerY)); 函数,它将返回带有对象的数组。比删除叠加对象和数组中的最后一个实例应该是最深的DisplayObject。
注意:最后一个实例可以是图形或类似的东西,因此您应该遍历父对象以查找最近的InteractiveObject。 另外,不要忘记父对象可以有 mouseChildren = false 或 mouseEnabled = false
答案 1 :(得分:1)
我也遇到过AS3事件的问题。我发现最好的方法是将eventListeners添加到调度事件的同一对象中。在您的情况下,将.addEventListener添加到舞台并将该函数作为函数发送到子剪辑。例如:
stage.addEventListener(MouseEvent.CLICK, object.object.clicked);
我希望这可能会有所帮助。我过去曾成功使用过这种方法。