Cascading click events to nested buttons in Flash 8
:: June 28, 2008
I am just putting these as notes to myself and for people who are looking for solutions. I spend a lot of time figuring out the this and thought this might help someone else as well.
Please note that this may not be the best solution to the problem and there may be some other solutions which is smarter than this. This was what I was able to cook out with the time I had. If someone else got a better solution to this, post a comment and I will edit the post to include your solution as well.
The Problem: If you have nested movieclips/buttons in your Flash Movie and have to attach onRelease (or for that matter any button events) to the movieclips nested within the parent movieclip then there is no way you can attach onRelease events to the child movieclips, since the parent movieclip will blanket all the calls - that being the top most element.
Let’s take this example:
In this case, if you specify a onRelease event for parent and then specify an onRelease calls to the other child movieclips, the onRelease event will work only for the parent and not for the child movieclips. This happens because the parent moviclip blankets all calls to the movieclips underneath it.
The only way out, in this case was to “move out” the child moviclips to the same level as the parent which wasn’t an option in my case.
Now for the solution:
There are two ways of working around this:
1) The easiest (and the nasty way) solution was to attach a movieclip of the same width and height of the actual movieclip and then assign onRelease event to the clone rather than the original. So, in this case your movie clip hierarchy would look like:
And you would write you action like:
parentMC.clone.onRelease, parentMC.Child1.clone.onRelease and so on.
Now you can target the actual moviclip by assigning a action on the lines of:
parentMC.Child1.clone.onRelease = function()
{
actualTarget = this._parent;
..
..
}
2) The other way is to use the hitTest, _xmouse, _ymouse property along with the getBounds and localToGlobal function and figure out where the _xmouse and _ymouse are based on hitTest. This is a complex route (and not so fool proof) and the steps to achieve this would be something on the lines of this:
- Create a movieclip and name it as pointer_mc (we need to use this movieclip as the mouse pointer).
- Hide the mouse and use this mc as your mouse pointer
- Attach a MouseListener for onMouseMove and move the pointer to where the current _xmouse and _ymouse are.
- Store all the valid movieclips (that are being targeted in an Array)
- Create a onMouseDown listener which will check for the hitTest on the target movieclips specified in the array against the pointer mc. Note that the first hit will always happen on the parent and then on the child – so you need to assign the final target to a variable which will contain the last click down.
- Do a getBounds on the final target you dervied on.
- Create a new point object with the xMin and yMin values
- Covert the point object to actual stage coordinates using the localToGlobal method.
- Check to see if your _xmouse is greater than myPoint._x and if your _xmouse is lesser than myPoint._x + finalTarget._width. This is where things gets tricky, now, your finalTarget’s width will be not just be its width but also the width of the child movieclips within it.
The actual code would look like this:
this.attachMovie("pointer_id", "pointer_mc", this.getNextHighestDepth());
Mouse.hide();
pointer_mc.swapDepths(10);
var mouseListener:Object = new Object();
mouseListener.onMouseMove = function()
{
pointer_mc._x = _xmouse;
pointer_mc._y = _ymouse;
updateAfterEvent();
}
var mArray:Array = [_root.mc1, _root.mc1.mc11, _root.mc1.mc11.mc112, _root.mc1.mc12];
mouseListener.onMouseDown = function()
{
for (var i=0; i<mArray.length; i++)
{
if (pointer_mc.hitTest(mArray[i]))
{
finalTarget = mArray[i];
}
}
var bounds_obj:Object = eval(finalTarget+".mc").getBounds();
var myPoint:Object = {x:bounds_obj['xMin'], y:bounds_obj['yMin']};
eval(finalTarget).localToGlobal(myPoint);
if ( _xmouse >= myPoint.x && _xmouse<= ( myPoint.x + ((eval(finalTarget))._width)) && _xmouse >= myPoint.y && _ymouse<= ( myPoint.y + ((eval(finalTarget))._height)))
{
trace("Correct :" + finalTarget);
}
else
{
trace("Wrong");
}
}
Mouse.addListener(mouseListener);
Now, the good news is if you are using AS3 then you need not worry about all these hacks you can directly use the MouseEvent.CLICK and detect the Mouse click and keep going forward. One more reason to switch to AS3.



