Skip navigation
Currently Being Moderated

TextField in MovieClip blocks MouseEvent.CLICK on vector background even with mouseChildren = false

Aug 27, 2012 4:13 PM

I'm trying to set up a custom button in Flash/AS3 but a TextField is causing problems with it no matter what I do. I'm wondering if anyone else has any ideas.

 

I have a MovieClip called TabSelector. Inside TabSelector there are two layers. The first layer has a TextField called lblLabel. The second layer has a MovieClip named background which is an instance of TabBackground.

 

TabBackground is a MovieClip containing a single vector shape. It has two frames (representing the "pressed" and "not pressed" states), with the vector a different color in each frame.

 

To keep the TextField from interfering with click events, I have TabSelector's mouseChildren property set to false. Now, I've done this with about a dozen custom buttons in this project, and it's always worked fine, but for this button, if I click anywhere in the region that the TextField occupies, TabSelector doesn't register a click at all (it still works if I click near the edge where the TextField doesn't reach). I've also tried setting mouseChildren to true and lblLabel.mouseEnabled to false but the same problem occurs.

 

The only difference between this button and all of the other buttons I've done is this one has a vector background and the others have imported PNG (i.e. bitmap) backgrounds.

 

Does a TextField cause a hole in any vector graphics behind it if you set its mouseEnabled property to false?

 
Replies
  • Currently Being Moderated
    Aug 27, 2012 5:14 PM   in reply to xTLS

    The text field isn't an input field by any chance?

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 28, 2012 10:27 AM   in reply to xTLS

    You can apply a listener to a shape but it won't register a MouseClick. You need to put the listener on the MovieClip that contains the shape.

     

    It's also a good idea to only set properties where needed rather than the proverbial carpet bomb technique of mouseChildren=false. That cascades so much it's hard to track. You should just set the selectable property to false on the TextField and listen for the MouseClick event on a valid object that can listen for it.

     

    Your other buttons are using Bitmaps and they can emit a MouseEvent which probably explains why they all work and this doesn't.

     

    Here's an example you can paste in frame 1 on a new AS3 document. I'm applying the listener to the MovieClip that contains nothing but a shape. The listener fires off just fine.

     

    If you comment out the listener on "mc" and uncomment out the listener on "myShape" you'll see even though it compiles, shapes won't dispatch on MouseEvents.

     

    import flash.display.Sprite;

    import flash.display.Shape;

    import flash.text.TextField;

    import flash.events.MouseEvent;

    import flash.display.MovieClip;

     

    // add button container

    var buttonContainer:Sprite = new Sprite();

    addChild(buttonContainer);

     

    // add text, dynamic default, cover 100x50 area,

    // background just to verify it exists

    var tf:TextField = new TextField();

    tf.text = "Example Text Field";

    tf.selectable = false;

    tf.width = 100;

    tf.height = 50;

    tf.border = true;

    tf.background = true;

    buttonContainer.addChild(tf);

     

    // add MovieClip wrapper for shape

    var mc:MovieClip = new MovieClip();

    buttonContainer.addChild(mc);

     

    // add semi-transparent red rectangle shape same size,

    // 100x50, inside a MovieClip over the text

    var myShape:Shape = new Shape();

    myShape.graphics.beginFill(0x990000,0.5);

    myShape.graphics.drawRect(0,0,100,50);

    myShape.graphics.endFill();

    mc.addChild(myShape);

     

     

    // listen to the MovieClip for clicks that only

    // contains a shape

    mc.addEventListener(MouseEvent.CLICK, handleClick);

     

    // if you comment the listener above and uncomment below you'll

    // see the shape does not fire off the handler

    //myShape.addEventListener(MouseEvent.CLICK, handleClick);

     

    function handleClick(e:MouseEvent):void

    {

        trace("Button Clicked, x:" + e.localX + " y:" + e.localY);

    }

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 28, 2012 11:14 AM   in reply to xTLS

    As the code above illustrates there is no issue with setting selectable=false, you don't need to nuke it all with mouseChildren=false and any MovieClip containing a shape (vector-only content) will fire off MouseClick events properly.

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 29, 2012 6:44 AM   in reply to xTLS

    It was relevant as you were asking if vectors would act differently than bitmaps, and yes, they do, and there is the proof. That was the point of it. I was also simply trying to illustrate how to nest a shape inside a clip to fix the issue. I did not read that you assigned the listener to the outer most clip however. I still disagree with mouseChildren. Chances are your issue was elsewhere.

     

    Happens to the best of us, especially on complex interfaces. Makes you want to start assigning trace statements and click handlers to objects near it to see what's covering it. Chances are it's a TextField gone wild elsewhere. Enabling borders or background on TextFields near it may reveal what is covering it.

     

    Aside that, event.target does give the child but you can always get the first clicked object using event.currentTarget. Keep that in mind. I never use event.target as you never know what object is going to fire back when things contain multiple display items. event.currentTarget will always send back the parent most clip that can respond to your click.

     

    Finally setting cacheAsBitmap on the TextField simply made it a bitmap in memory and therefore would act exactly like any other bitmap, including emitting MouseEvents, unless disabled via mouseChildren=false or mouseEnabled=false.

     
    |
    Mark as:
  • Currently Being Moderated
    Aug 29, 2012 11:57 AM   in reply to xTLS

    If you're directly coding a new 3d openGL engine saving that performance might make sense but I wouldn't kill yourself with it . Todays systems will have little to no noticable difference outside epic scale interfaces and intense vector/3d processing.

     

    As for a bit of time savings you can set the "useCapture" argument to true in addEventListener() to stop the event during the capture phase and stop the propagation of itself or all other events overall with either stopPropagation() or stopImmediatePropagation() respectively inside the listener function.

     

    Try those in your tests and see if you can shed a higher number. An event and listener that only cared about the fastest click response would look something like this:

     

    a.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, true, 0, true);

    b.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler2, false, 0, true);

     

    function mouseDownHandler(e:MouseEvent):void

    {

         // only care about the mouse event, stop all other events and this event further

         e.stopImmediatePropagation();

     

         //  your code

    }

     

    function mouseDownHandler(e:MouseEvent):void

    {

         //  your code

    }

     
    |
    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (0)

Answers + Points = Status

  • 10 points awarded for Correct Answers
  • 5 points awarded for Helpful Answers
  • 10,000+ points
  • 1,001-10,000 points
  • 501-1,000 points
  • 5-500 points