【问题标题】:Detect Mouse leave stage while dragging in Actionscript 3在 Actionscript 3 中拖动时检测鼠标离开阶段
【发布时间】:2010-12-06 12:18:41
【问题描述】:

Event.MOUSE_LEAVE 在 Actionscript 3 中很棒,但如果用户按住左(或右)鼠标按钮,它似乎不会触发。

有没有办法检测鼠标按住时鼠标是否离开 Flash 影片?或者如果它是在 Flash 电影之外发布的?

【问题讨论】:

    标签: flash actionscript-3 events mouseevent


    【解决方案1】:

    要获得所有这些,需要一点技巧。您必须存储鼠标是否离开舞台并相应地处理Event.MOUSE_LEAVE 事件。这样做可以为您提供所有正常的鼠标功能,包括不会因为鼠标离开舞台而停止拖动。由于用户可能会回到舞台上并继续拖动,因此它会一直等待,直到用户在舞台上或舞台外释放鼠标。

    var mouseOffStage:Boolean;
    
    var bonk:YourDisplayObject = new YourDisplayObject()
    addChild(bonk);
    bonk.addEventListener(MouseEvent.MOUSE_DOWN, function():void {
      mouseOffStage = false;
    
      bonk.startDrag();
    
      stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
      stage.addEventListener(Event.MOUSE_LEAVE, mouseLeave);
      stage.addEventListener(MouseEvent.MOUSE_OUT, mouseOut);
      stage.addEventListener(MouseEvent.MOUSE_OVER, mouseOver);
    })
    
    private function mouseUp(e:MouseEvent) :void {
      trace("Mouse Up On Stage")
      bonk.stopDrag()
    }
    
    private function mouseLeave(e:Event) :void {
      if(mouseOffStage){
        trace("mouse up and off stage");
        bonk.stopDrag();
      }else{
        trace("mouse has left the stage");
        //no reason to stop drag here as the user hasn't released the mouse yet
      }
    }
    
    private function mouseOut(e:MouseEvent) :void {
      mouseOffStage = true;
      trace("mouse has left the stage")
    }
    
    private function mouseOver(e:MouseEvent) :void {
      mouseOffStage = false;
      trace("mouse has come back on stage");
    }
    

    黑客是MOUSE_LEAVE 事件,而不是MOUSE_UP 事件,在鼠标离开舞台时被触发,因此您必须跟踪鼠标在释放时是否已经离开舞台。

    拖动完成后,您当然希望删除与检测鼠标移出和鼠标抬起相关的所有事件侦听器,但为了便于阅读,省略了该代码。

    【讨论】:

    • 言语无法真正表达我已经搞砸了多久,我很高兴我偶然发现了这个答案。
    • 在 Flash 15(或更早版本)中,mouse-up out-of-stage 不会产生 mouse-leave(正如 greggreg 建议的那样),而是 mouse-up。桑德拉·博洛克斯。只需在 mouseMove 中检查鼠标(舞台)坐标并与舞台尺寸进行比较即可了解是否进入舞台......!
    【解决方案2】:

    这就是我的工作:

    mc.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
    
    private function onMouseDown(_e:MouseEvent):void
    {
        mc2.startDrag(params);
    
        stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
        stage.addEventListener(Event.MOUSE_LEAVE, onMouseLeave);
        stage.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
    }
    
    private function onMouseUp(_e:MouseEvent):void
    {
        ms2.stopDrag();
    }
    
    private function onMouseLeave(_e:Event):void
    {
        mc2.stopDrag();
    }
    
    private function onMouseOut(_e:MouseEvent):void
    {
        if (e.stageX <= 0 || e.stageX >= stage.stageWidth || e.stageY <= 0 || e.stageY >= stage.stageHeight)
        {
            mc2.stopDrag();
        }
    }
    

    【讨论】:

      【解决方案3】:

      这里有几个棘手的陷阱不要落入:

      奇怪的是,在 Chrome + Firefox 中,对于 WMODEOPAQUETRANSPARENT 没有调度 MOUSE_LEAVE 事件。它只是不会触发 - 鼠标向下或向上。

      使用WINDOW 可以正常工作。那个我花了很长时间才发现! grr...http://bugs.adobe.com/jira/browse/FP-892


      其次,确保您使用Event 作为Event.MOUSE_LEAVE 处理程序的参数类型,而不是MouseEvent。如果您尝试使用e:MouseEvent 处理MOUSE_LEAVE,您将收到一个您可能永远不会看到的错误(除非您使用的是调试Flash 播放器)。这是一个非常容易犯的错误,因为您可能将所有其他处理程序都指向同一个方法。

      这就是我的工作:(只需从 mouseLeave(e:Event) 调用我的主要 endDrag

      stage.addEventListener(MouseEvent.MOUSE_MOVE, drag);
      stage.addEventListener(MouseEvent.MOUSE_UP, endDrag);
      stage.addEventListener(Event.DEACTIVATE, endDrag);
      stage.addEventListener(Event.MOUSE_LEAVE, mouseLeave);
      
      private function mouseLeave(e:Event):void
      {
          endDrag(new MouseEvent("MOUSE_LEAVE"));
      }
      
      public function endDrag(evt:MouseEvent):void
      {
          /// handle end drag
      }
      

      【讨论】:

      • .. 行 "stage.addEventListener(Event.DEACTIVATE, endDrag);" ,这是什么活动?
      • 很有趣,你说要小心 MOUSE_LEAVE 作为 MouseEvent 参数传递,但你在 Event.DEACTIVATE -> endDrag 上犯了同样的错误。 :-)
      • 糟糕。我为它逍遥法外将近四年:)
      【解决方案4】:

      我在必须构建到 Flex 应用程序中的 PDF 类型查看器中遇到了类似的问题。即使鼠标离开舞台或浏览器窗口,我希望平移功能仍然有效。以下是我完成此操作的方法,我更改了代码以删除对 Flex 框架类的引用,因此这应该适用于任何 AS3 项目。在mouseDown 上,我将开始在计时器上跟踪这些值。 _client 可以是目标阶段中的任何flash.display.DisplayObject。在我的情况下,它是一个 Flex mx.controls.SWFLoader 对象,但在你的情况下,我想它是拖动目标:

      private function get currentMouseX():Number
      {
           return _client.stage.mouseX; 
      }
      
      private function get currentMouseY():Number
      {
           return _client.stage.mouseY; 
      }
      

      stage.mouseXstage.mouseY 值是相对于舞台定义的,无论鼠标是在舞台上还是在浏览器窗口中(至少在 Flash Player 10 中,我还没有在早期的 Flash Player 版本中测试过)。要查看鼠标是否在舞台外,只需测试并查看这些值是否在舞台内,如下所示:

      if (currentMouseY < 0 || 
          currentMouseY > _client.stage.height || 
          currentMouseX < 0 || 
          currentMouseX > _client.stage.width)
      {
           // Do something here
      }
      

      编辑:关于在舞台外检测mouseUp事件,如果你在舞台上注册一个监听器,即使事件发生在舞台或浏览器之外,也会发出mouseUp。这是我如何处理事件函数的代码以供参考。 _client 对象可以是任何flash.display.DisplayObject

       // attach the events like so when you initialize
       _client.addEventListener(MouseEvent.MOUSE_DOWN  , handleMouse);   
       _client.addEventListener(MouseEvent.MOUSE_OUT   , handleMouse);
       _client.addEventListener(MouseEvent.MOUSE_OVER  , handleMouse);
      //
      
      // and handle them like this:
       private function handleMouse(e:MouseEvent):void
       {
            switch(e.type)
            {
      
                case "mouseDown":
      
               // add listeners, notice the mouse move and mouse up are 
               // attached to the stage, not the display object this way
               // events are issued regardless of whether the mouse is in 
               // the stage or even within the browser window
      
               _client.stage.addEventListener(MouseEvent.MOUSE_UP, handleMouse);
               _client.addEventListener(MouseEvent.CLICK, handleMouse);      
               _client.stage.addEventListener(MouseEvent.MOUSE_MOVE, handleMouse);    
      
      
               // remove listeners     
               _client.removeEventListener(MouseEvent.MOUSE_DOWN, handleMouse); 
      
               //
               // commands / actions 
      
               break;
      
      
               case "mouseUp":
      
               // add listeners
              _client.addEventListener(MouseEvent.MOUSE_DOWN, handleMouse); 
      
      
               // remove listeners 
               _client.stage.removeEventListener(MouseEvent.MOUSE_UP, handleMouse);
               _client.stage.removeEventListener(MouseEvent.MOUSE_MOVE, handleMouse);    
      
      
               // commands/actions 
      
               break;
      
      
               case "click":
      
      
               // add listeners
               _client.addEventListener(MouseEvent.DOUBLE_CLICK, handleMouse);
      
      
               // remove listeners    
               _client.removeEventListener(MouseEvent.CLICK, handleMouse); 
      
      
               // commands / actions
      
               break;
      
               case "mouseMove":
      
               // add listeners
      
      
               // remove listeners
               _client.stage.removeEventListener(MouseEvent.MOUSE_MOVE, handleMouse);
               _client.removeEventListener(MouseEvent.CLICK, handleMouse);   
      
      
               // commands 
      
               break;
      
               case "mouseOut":
      
               // add listeners
      
      
               // remove listeners
      
               // commands / actions
      
               break;
      
               case "mouseOver":
      
               // add listeners
      
      
               // remove listeners
      
      
               // commands /actions
      
               break;
           }
       }
      

      编辑:删除了对 Flex 框架类的引用 编辑:我记得当应用程序在 Mac OSX 上的 Safari 浏览器中运行时,浏览器窗口之外的事件可能会出现一些问题。如果您使用它,请确保在该浏览器中测试此代码。这在我的应用程序中不是问题,所以我没有进一步研究这个问题。

      【讨论】:

      • 我进行了一些编辑以包括额外的代码和解释,以及删除对 Flex 框架类的引用。希望这会有所帮助。
      【解决方案5】:

      如果您在拖动影片剪辑的地方做某事,这似乎工作得很好。

      stage.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
      

      编辑 - 没关系

      【讨论】:

      • 如果你拖动的东西总是在鼠标下方,那就行了。但就我而言,它是用于水平滚动条的。问题是,如果您拖动滚动条,然后向上或向下移动鼠标(离开滚动条),那么它会触发该事件。
      • 啊,是的,我明白你的意思了:S
      • 也许如果所有其他方法都失败了,您总是可以在 ENTER_FRAME 上检查鼠标坐标并查看它们是否在舞台之外?
      • 检查鼠标坐标是否在舞台外是行不通的,因为当鼠标离开舞台时闪光灯停止更新坐标。所以他们永远不能“在舞台之外”。
      • 将 mouseUp 而不是 mouseOut 侦听器附加到舞台将起作用。请参阅我的代码答案。
      【解决方案6】:

      有没有办法检测鼠标按住时鼠标是否离开 Flash 影片?

      我不知道

      或者如果它是在 Flash 电影之外发布的?

      Event.MOUSE_LEAVE 确实会在您在室外释放时发生。

      更多信息在这里 http://blog.zupko.info/?p=3 见 JIMISAACS 评论。

      【讨论】:

        【解决方案7】:
            var youMax_X:Number; //set this var to Max x
            var youMax_Y:Number; //set this var to `enter code here`Max y
        
            var dragBounds:Rectangle = new Rectangle(0,0,youMax_X,yourMax_Y);
        
            stage.addEventListener(MouseEvent.MOUSE_DOWN,handleDown);
            stage.addEventListener(MouseEvent.MOUSE_UP,handleUp);
        
        
            private function handleDown(e:Event):void{
                    this.startDrag(false,dragBounds);
            }
            private function handleUp(e:Event):void{
                this.stopDrag();
            }
        

        【讨论】:

        • 这并不能真正回答所提出的问题。
        • 请尽量避免发布纯代码答案。解释你的代码做什么以及如何做。描述它如何解决您正在回答的问题中提出的问题。
        • 上帝的震动不言自明
        • 这甚至比我的解决方案更好,但我的优势在于它可以与任何显示对象(即位图)一起使用,其中 'startDrag' 是一个 Sprite-only 函数
        【解决方案8】:

        这是正确的答案。您将 DisplayObject 传递给的自定义类并将其拖动到鼠标向上或鼠标移出舞台。随意定制:

        package fanlib.gfx
        {
            import flash.display.DisplayObject;
            import flash.display.Stage;
            import flash.events.Event;
            import flash.events.MouseEvent;
            import flash.geom.Point;
            import flash.ui.Mouse;
        
            public class Drag
            {
                private var obj:DisplayObject;
                private var point:Point = new Point();
                private var stg:Stage;
        
                public function Drag(obj:DisplayObject)
                {
                    this.obj = obj;
                    stg = Stg.Get();
                    stg.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
                    stg.addEventListener(MouseEvent.MOUSE_UP, stopDrag);
                    //stg.addEventListener(Event.MOUSE_LEAVE, stopDrag); // sh*t just won't fire
                    point.setTo(stg.mouseX, stg.mouseY);
                }
        
                private function mouseMove(e:MouseEvent):void {
                    if (stg.mouseX <= 0 ||
                        stg.mouseY <= 0 ||
                        stg.mouseX >= stg.stageWidth ||
                        stg.mouseY >= stg.stageHeight) {
                        stopDrag();
                        return;
                    }
                    obj.x += stg.mouseX - point.x;
                    obj.y += stg.mouseY - point.y;
                    point.setTo(stg.mouseX, stg.mouseY);
                }
        
                public function stopDrag(e:* = null):void {
                    stg.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
                    stg.removeEventListener(MouseEvent.MOUSE_UP, stopDrag);
                    //stg.removeEventListener(Event.MOUSE_LEAVE, stopDrag);
                }
            }
        
        }
        

        【讨论】:

        • 鼠标 x/y 可以小于 0 并且大于舞台宽度/高度吗?
        • 是的,如果按下鼠标按钮
        猜你喜欢
        • 2010-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多