SXSW Panel Picker →← Adobe Switchboard

Ensnaring mouseEnabled

A lot of what we do here at the Spaceship involves complex SWFs loaded in and layered on top of other SWFs. We wind up with a lot of buttons nested underneath of movieclips nested inside of SWFs.

When we got to handling mouse interaction in AS2, this was fine so long as a button wasn’t layered on top of another button. But in AS3 it’s a different ball of wax — each DisplayObject has a mouseEnabled property, which is set to true by default. mouseEnabled means that the DisplayObject in question *can* react to mouse events.

This can be lead to some tricky and irritating issues. Hit the jump for specifically what is happening and how to fix it.


The rule of thumb is more or less this:

When a mouse event happens, the DisplayObject underneath the mouse at the highest depth with mouseEnabled set to true will fire a MouseEvent, which will relay to it’s parent, and it will go all the way down to the stage.

Consider this: MovieClip A is on the topmost layer. MovieClip B has a MouseEvent.CLICK listener. MovieClip A overlaps MovieClip B.

Any time a user clicks on MovieClip A it will hear the MouseEvent and sending it down the chain… MovieClip B would never hear it. This effectively creates the “I’m listening for the mouse but nothing happens for no reason” bug. By setting MovieClip A to mouseEnabled=false, all is well. Note that if MovieClip A had anything nested inside of it, they too would have to be disabled. You can do this either with mouseEnabled=false on each of them painstakingly or by setting MovieClip A’s mouseChildren=false.

So okay! We know what the problem is… a MovieClip can block the mouse from another movieclip. But most of what we’re building in Flash is far more complex than one MovieClip on top of another… is there an easy way to find the culprit of mouse blocking? Indeed there is! Sort of. Just drop this code on your main timeline (or your root class, if you prefer):


stage.addEventListener(MouseEvent.CLICK,_checkMouseEventTrail,false,0,true);
function _checkMouseEventTrail($e:MouseEvent):void
{
var p:* = $e.target;
while(p)
{
trace(">>", p.name,": ",p);
p = p.parent;
}
};

What we’re doing in the above is listening to the stage for any mouse interaction and then outputting the path on the DisplayList from the origin of the event all the way down to the stage.

We use this as a utility to help us figure out what DisplayObject is blocking our way to the DisplayObjects we actually care to listen to.

August 5th, 2008  by Jamie  /  9 Comments

Comments on “Ensnaring mouseEnabled”

  1. Another way to do this would be to snag the currentTarget property of the MouseEvent.CLICK object.

    Jeffery on August 5th, 2008 at 5:34 pm
  2. @Jeffery: Surely, but neither target nor currentTarget zeroes in on where the rogue DisplayObject starts — what SWF it lives in, for example. This loop might seem excessive, but its super helpful finding the root of the problem, literally. :)

    Jamie Kosoy on August 5th, 2008 at 6:17 pm
  3. “by setting MovieClip A’s mouseChildren property to true.”

    i think it should say “setting … mouseChildren property to FALSE.”, isn’t it.

    phil

    Philipp on August 6th, 2008 at 4:25 am
  4. What about Sprite::getObjectsUnderPoint() + some filtering on mouseEnabled?

    maliboo on August 6th, 2008 at 5:26 am
  5. @Philipp: Yes you’re right. I’ll update that. Good catch!

    @mailiboo: getObjectsUnderPoint() could work too, absolutely. I don’t know if there’s a performance benefit one way or the other — I typically just throw the stage listener in for the duration of my debugging and then remove it anyway. Different ways of skinning a cat, I suppose.

    Jamie Kosoy on August 6th, 2008 at 12:47 pm
  6. Hi. I love your blog, it’s the best, but… It burns my retina, the black with white text. Styleshifter would be nice. :)

    John on August 21st, 2008 at 2:44 am
  7. on a mac
    [control-option-command-8]
    switches your display to black on white.

    zahir on September 1st, 2008 at 2:19 am
  8. Hey Jamie.
    I think this is a good post; helpful for many Flashers out there hopefully, discovering this pesty issue. I’ve gotten into the habit of making a separate “hitArea” movie clip without any other objects in it to act as the movie clip receiving the events and listeners. Also catching myself saying “oh, god dammit” to myself and quickly typing in mouseEnabled and mouseChildren to false. ;)
    Christian

    Christian Kragh on September 4th, 2008 at 3:31 pm
  9. Recently I made a library that solves such issue http://labs.wispagency.com/?p=15 , of course there are always alternatives like getObjectsUnderPoint but it is always good to be aware more different ways of solving a problem.

    Aleksandar Andreev on September 15th, 2008 at 7:38 pm