2012-12-10 79 views
1

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

我试图在正确的位置手动发送MouseEvent来的阶段:

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

由于舞台没有点击的事件处理程序,我预计该事件在层次结构传播到按钮,将实际上处理它(当我物理地点击鼠标时)。但是,它没有。

我知道我可以在按钮上发送事件,但是不会检测对象是否被阻塞。 有没有一些方法来模拟鼠标事件,以便它们能够在层次结构中正确传播?

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

编辑2: 如果有一个部分透明的覆盖与我以前的解决方案没有奏效一个点击处理程序,就像一个带有几个Shapes的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; 
} 

不幸的是,仍然未覆盖的至少一个的情况下:如果对象是另一对象的掩模。我不知道如何检查这一点,因为它可能会掩盖显示层次结构中的任何位置。我将不得不遍历整个树并检查每个显示对象以找出它。

所以,我的问题仍然存在:是不是有一个更简单的方法来做到这一点?

回答

1

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

注意:最后一个实例可以是图形或类似的东西,所以您应该循环父对象以查找最近的InteractiveObject。 另外,不要忘了父对象可以有mouseChildren =假将mouseEnabled =虚假

+0

我看不出如何解决我的问题。该函数返回的数组没有任何特定的顺序,至少文档没有为它指定任何顺序。所以,我仍然需要弄清楚这些对象的显示顺序,这些基本上可以归结为我已有的东西。 –

1

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

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

我希望这可以帮助。过去我已经成功地使用了这种方法。

+0

我无法更改添加事件侦听器的地方,因为我想对现有代码运行测试。除此之外,我不认为将所有事件处理程序直接放在舞台上是一种可扩展或可维护的方法...... –