Flash / AS3 - How to Disable Child SWF Mouse Clicks Without Disabling Mouse Hover Events - actionscript-3

I have a flash browser application that loads in a child swf using a Loader object.
The child swf has a mouseclick listener that calls nativateToUrl, and opens a new web page. It also contains mouse hover events that make things in the swf move around.
This application that does the loading is like a container for the child swf and should open a different web page when it is clicked. So essentially I want to suppress the child swf mouseEvent and listen for the mouse click on the container swf, opening the new URL.
I have heard of other people putting an invisible sprite over the original content so that the child swf doesn't actually catch a mouseclick event. However, this won't work in my case because then it doesn't get the mouse hover events either. I want the mousehover events to go through and make the things in the child swf move but also suppress the click event.
So, for all the flash masterminds out there... is this possible? And how can I do it?
:) thanks.

If you want to suppress all MouseEvent.CLICK events from reaching a loaded SWF, you can do the following:
Let's assume you have the following setup:
var loader:Loader = new Loader();
loader.load(new URLRequest("child.swf"));
addChild(loader);
What you can do, is listen on the capture phase for a click event on the Loader:
loader.addEventListener(MouseEvent.CLICK, handler, true);//the third parameter (true) tells flash to listen on the capture phase of an event's lifecycle
Then in the click handler from that, cancel the event so it doesn't propagate down to the loaded SWF:
function handler(e:Event):void {
e.stopImmediatePropagation();
}
If you don't understand the phases of events, this diagram from Adobe may help:
Source
As an aside, if you wanted to suppress all mouse stuffs from the SWF, a much better way (instead of adding an invisible sprite) is to just do this:
loader.mouseChildren = false;

Related

How to capture all keyboard input to a custom element?

Here is my problem: I've got a swf loaed inside my loader an in that swf I have a keylistener:
stage.addEventListener(KeyboardEvent.KEY_DOWN, this.__onKeyDown, false, int.MAX_VALUE);
Now I'm adding a TextInput to this stage and I would like this input to catch all keyboard events while I'm focusing it. Is it possible to do so that native __onKeyDown will not fire until my TextInput has lost focus?
Thank you for your answers and sorry for my bad english.
You could give your listener higher priority (which you are), and stopAllPropogation in your handler. I've never tried this with an embedded swf so if it doesn't work right away, you could also try listening to the event in the capture phase (third parameter in addEventListener).
function __onKeyDown(e:KeyboardEvent):void {
e.stopImmediatePropagation();
//rest of you handler code here
}

Unloading external SWF files

I'm loading multiple swf files from the main menu which is never unloaded. I've done this with the following code... Only issue is that instead of unloading to the main menu I just see a white screen as if nothing is loaded.
function BackToMenu(i:MouseEvent):void
{
var BaseMovie:MovieClip = parent.parent as MovieClip;
BaseMovie.parent.removeChild(BaseMovie);
}
EDIT: I'll explain from the start I have a MainMenu.swf. The games are loaded from MainMenu.swf when the button relating to the game is clicked. When a game button is clicked on MainMenu.swf the game loads. When the player completes a game they are presented with the exit button which unloads the current game and shows the MainMenu.swf without having to re-load it.
First, you should remove one parent to make sure you are actually removing only the game:
function BackToMenu(i:MouseEvent):void
{
var BaseMovie:MovieClip = parent as MovieClip;
BaseMovie.parent.removeChild(BaseMovie);
}
This should take care of your most pressing problem, and allow you to return to the menu. You have, however, not really unloaded the game, but only removed it from the display list. This often means, that there are still sounds running, active key and/or mouse listeners, etc. - these must all be taken care of!
And, like I said, this will only fix your immediate problem. It is, however, neither a permanent solution, nor a good one: Since the main SWF is responsible for loading the games, it should also be responsible for disposing of them. You should put cleanup code into your game, but it should only be concerned with stopping any running scripts, sounds, etc. - simple rule: anything that is started within the game, should be stopped within the game. But it should not try to access objects further up in the display hierarchy, or try to unload itself.
The much better way to do this is by replacing all the above code, and letting the main SWF take care of removing the game, as well as unloading it from memory. For this, you have to do three things:
Instead of writing actual removeChild calls, etc., let your button dispatch a custom event to notify the main SWF that it should now be removed:
function onBackButtonClicked( event:MouseEvent ):void {
destroyGame(); // this would be the function that stops all the scripts
dispatchEvent( new Event( "FINISH_GAME", true ) );
}
Note that "FINISH_GAME" is now a "bubbling" event, i.e. it travels downward in the display hierarchy. We can now listen for this event in any ancestor display object containing the game.
In your main SWF, add an event listener to the Loader when the game was successfully loaded. This is done in the event listener that is called when the load process completes:
function onLoadComplete( event:Event ):void {
var loader:Loader = event.target.loader;
loader.addEventListener( "FINISH_GAME", onFinishGame, true );
}
Use the corresponding event handler to remove the game clip:
function onFinishGame( event:Event ):void {
var loader:loader = event.currentTarget;
loader.parent.removeChild( loader );
loader.unloadAndStop();
}
A few more things to consider:
The naming conventions in ActionScript advise us to use lower case names for methods and variables, and upper case only for types.
The same naming conventions suggest we use either "on" or "handle" as a prefix for event listeners, along with the name of the event. Thus, it should be onBackToMenu or rather, onBackButtonClicked, etc.
Since I don't know anything about the code you use for loading, I just assumed you have a complete listener, and you don't keep references to the loader. If you use a member variable, you can use that instead of event.target, resp. event.currentTarget.

AS3 ScrollPane dispatch event to content

i've loaded external swf into ScrollPane and i need to dispatch click event to this external swf. is it possible? ScrollPane.content.dispatchEvent(new MouseEvent(MouseEvent.CLICK,true)); doesn't work. this is obvious cuz ScrollPane.content is an DisplayObject and it have not CLICK event...
I can't use MovieClip as container for external swf cuz external swf is a documents converted to swfs using openoffice and it doesn't want to load inside MovieClip but perfectly loads inside ScrollPane and react on mouse clicks,but i need to simulate mouse click on it.
so you're saying that the following won't work or you haven't tried it?
var exSWF:MovieClip = MovieClip( ScrollPane.content );
or
var exSWF:Sprite = Sprite( ScrollPane.content );
Not sure to understand what you mean when you say that your external SWF won't load into a MovieClip.
Do you know what version of Actionscript was used for the external SWF, you can check that in debug mode by looking at the properties of the ScrollPane.content?

Flash Double-click an externally loaded SWF

I've got a class (which extends MovieClip) that loads in an external SWF (made in pdf2swf). That is added to another class which has declared doubleClickEnabled = true and I'm listening for DOUBLE_CLICK events.
The problem is when the SWF is loaded my code picks up no DOUBLE_CLICK events, only CLICK events. I've tried it without adding the SWF to the stage and it does pick up DOUBLE_CLICK events.
Anybody come across this before?
class ParentClass{
...
public function ParentClass(){
...
mcToLoadSWF = new MovieClip();
addChild(mcToLoadSWF);
doubleClickEnabled = true;
addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler);
...
}
}
I've also tried adding the event listener to the mcToLoadSWF as well. No dice.
What's happening here is that what you are double-clicking is the loaded clip, which is not doubleClickEnabled and therefore the event is not generated, and is not bubbled up to your clip like the other mouse events. Set mouseChildren to false to not send mouse events to the children of your loader, but of course this means that any interactivity in them will not work.

'glasspane' for as3 to intercept events to everything on stage?

Is there something like the java 'glasspane' in as3?
The glass pane is useful when you want to be able to catch events or paint over an area that already contains one or more components. For example, you can deactivate mouse events for a multi-component region by having the glass pane intercept the events. Or you can display an image over multiple components using the glass pane. http://java.sun.com/docs/books/tutorial/uiswing/components/rootpane.html
Why do this? While some animations are underway in flash, I want to prevent any mouseevents from firing. I could remove all listeners systematically, then re-add them after the animation, but if there is something like a glasspane, it might be an easier way to achieve the same effect.
My current thinking is to:
add a sprite to the stage
stretch to width and height of the stage,
give the sprite the highest z-order,
grab all events on this sprite, and stop their propagation?
if you set
enabled=false;
mouseChildren=false;
on to the top most DisplayObject it should disable all mouse events for your app. I've used it and it works a treat.
For a more specific approach, e.g. only block clicks but let mouse down etc. through I use this approach. It uses a 'clickBlocker' stage event handler during capture phase, stopping propagation to any other object.
public function blockClicks():void{
if(!stage) return;
stage.addEventListener(MouseEvent.CLICK, clickBlocker, true); //useCapture!
}
private function clickBlocker(event:MouseEvent):void{
trace("Me (the stage) gets the "+event.type+" first, and I block it #"+event.stageX+"/"+event.stageY);
event.stopImmediatePropagation();
}