How to access parent movieclip's variable from loaded swf - actionscript-3

I have a swf which load an external swf. The loader swf has a variable which i want to access from the loaded swf. I use MovieClip(parent.parent).myVar but it return this error
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at card01_fla::MainTimeline/frame1()
The loader swf has a custom Document Class which i think is the problem.
Thanks in advance.
EDIT
This is the as of the main swf
package
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.net.URLRequest;
import flash.text.TextField;
/**
* ...
* #author chchrist
*/
public class CardSender extends Sprite
{
private var loader:Loader;
private var viewButtonArray:Array;
private var sendButtonArray:Array;
private var cardContainer:Sprite;
public var testVar:String
public function CardSender() {
testVar = "it worked!!!";
init();
}
private function init() {
viewButtonArray = [cardsenderMC.view01, cardsenderMC.view02, cardsenderMC.view03, cardsenderMC.view04];
for each( var viewButton in viewButtonArray) {
viewButton.buttonMode = true;
viewButton.addEventListener(MouseEvent.CLICK, onViewClick);
}
}
private function onViewClick(e:MouseEvent):void {
var cardName = "card"+e.target.name.substring(4)+".swf";
loader = new Loader();
loader.load( new URLRequest(cardName));
loader.contentLoaderInfo.addEventListener(Event.INIT, onCardInit);
}
private function onCardInit(e:Event):void {
addChild(loader);
var content:* = loader.content;
content.closeButton.addEventListener(MouseEvent.CLICK, onCloseClick);
}
private function onCloseClick(e:MouseEvent):void {
removeChild(loader);
}
}
}
and I am trying to access the test variable from the loaded swf with this code
trace(MovieClip(parent.parent).testVar);
EDIT#2
If I addChild(loader) not in the onCardInit but in the onViewClick and in the first frame of the loaded swf i have Object(parent.parent).testVar it works...but why it doesn't want to be inside the onCardInit function?

You have just one loader variable and you're creating four Loader instances and assigning them to it - so if you are clicking all four of them in quick succession, the loader variable will effectively contain the Loader object corresponding to the last click. All your addChild calls will act on that same Loader object - the others will not be added and their parents will continue to be null
Make the following changes to the code:
private function onCardInit(e:Event):void
{
addChild(LoaderInfo(e.currentTarget).loader);
var content:DisplayObject = loader.content;
trace(content);
trace(content.closeButton);
content.closeButton.addEventListener(MouseEvent.CLICK, onCloseClick);
}
private function onCloseClick(e:MouseEvent):void
{
trace(e.currentTarget);//should be the closeButton
trace(e.currentTarget.parent);//should be the loaded swf
trace(e.currentTarget.parent.parent);//should be the Loader object that loaded it
//The following will work only if last three traced correctly
removeChild(e.currentTarget.parent.parent);
}
Answer to the following update in the question:
If I addChild(loader) in the onViewClick instead of onCardInit, then Object(parent.parent).testVar in the first frame of the loaded swf works. Why doesn't it work if I addChild inside the onCardInit function?
Again, that might be because you are adding a different loader object - are you clicking on more than one viewbuttons? Click on a view-button and wait till it is loaded to see it working.

parent.parent is wrong.
try using:
MovieClip(MovieClip(e.currentTarget.parent).parent).myVar ;
You have to cast the first parent to some class like MovieClip and then get this new MovieClip's parent and then getting inside variable.

try tracing parent and parent.parent, I'm sure it's because of an aditional "parent"

loader.content is NOT a movieclip, so it doesn't have the same capabilities. try
myLoadedClip:MovieClip = MovieClip(loader.content);
then your myLoadedClip.parent.myVar should show up
you might want your handler to fire on a Event.COMPLETE instead of on an Event.INIT

This only line code in loaded swf resolves it! ;)
MovieClip(MovieClip(parent.parent).root).play();

Related

Avoid null object reference errors in code inside the child SWF

I'm creating a global loader that loads different SWFs.
I don't have access to the child SWFs code.
I'm trying to avoid null object reference errors in code inside the child SWF that may reference "stage" etc.
I've added all the possible event listeners, added try/catch, tried all the applicationDomains and LoaderContexts permutations. for example:
applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
var con:LoaderContext = new LoaderContext(false, applicationDomain );
con.allowCodeImport = true;
var _loader:Loader = new Loader();
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoad);
_loader.load( new URLRequest(fileName + ".swf"), con);
I just can't catch the error or disable/remove the code from such a SWF.
for example, the following Main class:
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public function Main() {
var h = this.stage.stageHeight;
trace(h);
}
}
}
will crush any SWF that will try to load it as part of another SWF.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Main()
Any help with catching the Error, disabling/removing the code or any other idea will be much appreciated.
Thanks.
Do you have access to the code in the child swf files? If so, you can do something like this:
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public function Main() {
if (stage) {
init();
}
else {
addEventListener(Event.ADDED_TO_STAGE, init);
}
}
public function init(evt:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// You can now access the stage here
}
}
}
This will hold off initializing the child object until the stage reference is set. For all child objects the constructor will be called first before the stage is set, so you can't rely on it being there in the constructor.

TypeError: Error #1009 with loading external SWF file

I was making 3D File Viewer in Flash Player with AS3.0
and i found AWD Viewer from Away3D Example File.
(http://awaytools.com/awaybuilder/tutorial-01/AwayBuilderTutorial01_SampleFiles.zip)
it works fine.
and i loaded it in my 'Main' swf file. but it's not work. it kept showing error to me.
error message is below
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at AWDViewer/initEngine()[C:\Users\wintec\Desktop\Flash3DViewer\source\AWDViewer.as:74]
at AWDViewer/init()[C:\Users\wintec\Desktop\Flash3DViewer\source\AWDViewer.as:57]
at AWDViewer()[C:\Users\wintec\Desktop\Flash3DViewer\source\AWDViewer.as:49]
and that error line is just this
line 74 : stage.scaleMode = StageScaleMode.NO_SCALE;
line 57 : initEngine();
line 49 : init();
and I know that error message mean there's no properties that name.
I checked that, there's nothing wrong.
also, when I loading another swf file in my 'Main'swf, that's works. weird...
I don't understand why this error kept showing.
please help me.
below code is from Main.as
package
{
import flash.display.MovieClip;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
public class Flash3DViewer extends MovieClip
{
private var _request:URLRequest = new URLRequest("AWDViewer.swf");
private var _loader:Loader = new Loader()
public function Flash3DViewer()
{
init();
}
private function init():void
{
stop();
_loader.load(_request);
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, initLoaded);
}
private function initLoaded():void
{
_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, initLoaded);
var extSwf = _loader.content as MovieClip;
swfContainer.addChild(extSwf);
trace("contents loaded");
}
}
}
I found the issue with your application based on the code you provided via DropBox. And just as I suspected, the stage property was being referenced before the object's addition to the stage was completed, which is why the null reference error was being generated.
The AWDViewer class was prematurely calling the stage property from one of the functions that is being called when the init function is called. I've updated the Flash3DViewer.as and AWDViewer.as files with the proper usage of the ADDED_TO_STAGE event so that this does not occur. I have also added comments to the code for you to follow along. Also, I had to modify the init function in the AWDViewer class to take a parameter of type Event to account for the fact that the function is now called when the ADDED_TO_STAGE event fires.
Flash3DViewer.as:
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
public class Flash3DViewer extends MovieClip
{
private var loader:Loader;
public function Flash3DViewer():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
loadSWF("AWDViewer.swf");
}
private function loadSWF(url:String):void
{
var urlRequest:URLRequest = new URLRequest(url);
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded, false, 0, true);
loader.load(urlRequest);
addChild(loader);
}
private function onLoaded(e:Event):void
{
var target:AWDViewer = e.currentTarget.loader.content as AWDViewer;
trace(target);
//target.init(); // no longer need to call the init function manually as the AWDViewer calls it when it 'knows' it has been added to the stage. This line can be deleted.
addChild(target);
}
}
}
AWDViewer.as:
public function AWDViewer()
{
/* Used ADDED_TO_STAGE event to know when to trigger the init
function call to avoid the null reference errors when accessing
the 'stage' property */
addEventListener(Event.ADDED_TO_STAGE,init);
// init(); // no longer need to manually call the init function as the ADDED_TO_STAGE event listener will take care of this. This line can be deleted.
}
/**
* Global initialise function
*/
public function init(e:Event):void
{
initEngine();
initListeners();
AssetLibrary.enableParser(AWD2Parser);
//kickoff asset loading
var loader:Loader3D = new Loader3D();
loader.load(new URLRequest("assets/monkey.awd"));
_view.scene.addChild(loader);
}
While I did attempt to compile the code above, and the null reference errors ceased to generate with my corrected code, there were some compiler errors on my machine because of the different configurations of our computers. You'll just need to ensure that these compiler errors do not appear on your machine.
Warning: Library path "C:\Users\wintec\Desktop\3D_VR\source\libs" does not resolve to a valid directory.
Warning: Library path "$(FlexSDK)/frameworks/libs/flex.swc" does not resolve to a valid file.
If you have any other questions, just let me know.
Cheers.
That error means that you are trying to access something which has not been instantiated. You should put some breakpoints and run your app in debug mode when you are not sure what exactly is null.
It's very likely that stage is null in your case. Stage property of DisplayObject is set to the instance of app's stage when this display object is added to stage. However, all parents of this display object should be added to the stage too. Thus, make sure that the instance of Flash3DViewer has the stage before loading AWDViewer.

How to listen to click event on a container which contains a Loader which loads a SWF?

I've simplified my problem into the following code.
It's an instance of Loader loading a SWF which is not in the current domain. I added this loader into a container, which is an instance of Sprite. I listened for the click event on the container in order to know if the user clicks the SWF. Looks like it doesn't work out.
So how do I know if the user clicks the loaded SWF file?
package {
import flash.display.Sprite;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.MouseEvent;
import flash.events.Event;
public class Main extends Sprite {
private var _container:Sprite;
private var _loader:Loader;
public function Main() {
_container = new Sprite();
_loader = new Loader();
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
_loader.load(new URLRequest("http://strip.taobaocdn.com/tfscom/T13sAUFIBXXXXtxVjX.swf"));
_container.addEventListener(MouseEvent.CLICK, onClicked);
_container.addChild(_loader);
addChild(_container);
}
private function onComplete(event:Event):void {
trace(_loader.contentLoaderInfo.width);
trace(_loader.width); // 0
trace(_container.width); // 0
}
// onClicked is never triggered in my case
private function onClicked(event:MouseEvent):void {
trace("clicked");
}
}
}
I asked my colleague to help dig into this problem. He told me that it has something to do with the Security issue.
I need to have a Security.allowDomain call in order to let the click event on the loaded SWF bubble up properly. Here's the code:
private function onComplete(event:Event):void {
Security.allowDomain(_loader.contentLoaderInfo.url)
}
Listen for the click on _loader.content won't always work. Say the loaded SWF only has a plain Bitmap on the stage. Because Bitmap doesn't inherit from InteractiveObject, it won't respond to click event.
So it's nice to have the click event listener attached to the _loader or the _container in this case and set the Security.allowDomain correctly.

AS3: How to access and control embedded sounds in an external swf?

I rarely use sounds in AS3/Flash. I am using Flash Pro CS6, but I can't seem to figure out how to access, control (play, stop, etc) sounds embedded in an external SWF loaded into the main SWF.
It's easy to control them when embedded on the main swf. However, on an externally loaded SWR, I get all kinds of errors. For this app, I really need to embed them in the external SWF.
I read several solutions, but none seem to work.
I embed the sound an mp3 file called soundSegment1.mp3 using Flash CS6 import tool and then open the actionscript properties panel on flash to select the class name: SoundSegment1. Then I edit the class code and create a file called SoundSegment1.as and it's saved right next to my document class main.as in the same directory. The code of the SoundSegment1 class looks like this:
package {
import flash.media.*;
public class SoundSegment1 extends Sound
{
public function SoundSegment1 ()
{
// no code in here
}
public function playSound()
{
var soundSegment1:Sound = new SoundSegment1();
var channel:SoundChannel = soundSegment1.play();
}
}
}
Then, in my main.as, I have done several attempts to play this sound such as:
var fileLocation:URLRequest = new URLRequest(SWFToLoad);
loader.load(fileLocation);
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressListener);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeListener);
loader.contentLoaderInfo.addEventListener(Event.INIT, initListener);
function initListener(e:Event):void // I also placed this code on the completeListener and it didn't work
{
loader.content.soundSegment1.playSound(); // doesn't work.
}
I get:
Line XXX 1061: Call to a possibly undefined method playSound through a reference with static type flash.display:DisplayObject.
or, I also read that I should be able to do something like this anywhere in the Main.as file:
var theClass:Class = Class(loader.content.getDefinitionByName("SoundSegment1"));
var theSound:theClass = new theClass();
theSound.play() //doesn't work either.
I also tried on the completeListener:
var TheClass:Class = e.target.applicationDomain.getDefinition("SoundSegment1") as Class;
var theSound:TheClass = new TheClass();
theSound.play() //doesn't work either.
I get:
ReferenceError: Error #1065: Variable SoundSegment1 is not defined.
at flash.system::ApplicationDomain/getDefinition()
I am stuck and I really need to get this to work. I would be genuinely grateful for your help.
Thank you in advance for any help provided. I really need to get it to work, because I can't simply embed them in the main SWF or load them individually externally one by one.
Thanks again!
user SnickelFritz from Kirupa gave me a fabulous answer with much easier code, which can be very powerful when using multiple sounds. This is just great, because you can use only one preloader per SWF, instead of having multiple loader for each file:
code for the main.as file
http://www.kirupa.com/forum/showthread.php?305098-Playing-a-embedded-sound-in-an-external-swf
package
{
import flash.display.*;
import flash.media.*;
import flash.events.*;
import flash.net.*;
public class Main extends MovieClip
{
var swf:MovieClip;
public function Main()
{
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoaded);
l.load( new URLRequest("child.swf") );
}
private function swfLoaded(e:Event):void
{
swf = e.target.content as MovieClip;
addChild(swf);
swf.playSound();
}
}
}
Code for the loaded swf "child.as"
package
{
import flash.display.*;
import flash.media.*;
import flash.events.*;
import flash.net.*;
public class Child extends MovieClip
{
private var s:Sound1;
private var sc:SoundChannel;
public function Child()
{
s = new Sound1();
sc = new SoundChannel();
// All of the following lines are actually optional, if all your graphic elements are already inside the swf prepared in flash pro
var g:Graphics = this.graphics;
g.beginFill(0x666666);
g.drawRect(0,0,550,400);
g.endFill();
}
public function playSound():void
{
sc = s.play();
}
}
}
User "kglad.com" on the Adobe Forums also gave me a good answer:
http://forums.adobe.com/message/5681137#5681137

Embedded .swf animation not stopping on stop() call?

I have a .swf animation that I created in Flash Professional. To use it in my actionscript project, I embed it as follows:
[Embed(source="../lib/fetching.swf")]
public var Fetching:Class;
I then create an instance and add it to the stage as follows:
//class variable
var mc:MovieClip;
mc = new Fetching();
this.addChild(mc);
This causes my animation to appear on the screen and loop indefinitely. However, when calling mc.stop(), the animation does not stop. I've tried removing the movieclip from the stage by calling removeChild(mc) but adding a listener on the ENTER_FRAME event told me the movieclip is still playing over and over.
you should set a Embed source mimeType, and you convert to ByteArray. and loaded. because you can't Direct Type Casting Fetching Class to MovieClip. If you define explicitly mimeType and convert by force, you'll get about TypeError #1034: Type Coercion failed: cannot convert YourProject_Fetching#108b780d1 to flash.display.MovieClip
refer a following code.
package
{
import flash.display.Loader;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.utils.ByteArray;
public class TestProject extends Sprite
{
[Embed(source="../lib/fetching.swf", mimeType="application/octet-stream")]
public var Fetching:Class;
public var loader:Loader = new Loader();
private var mc:MovieClip;
public function TestProject()
{
loader.loadBytes( new Fetching() as ByteArray );
loader.contentLoaderInfo.addEventListener(Event.INIT, onSwfLoaded);
this.addChild(loader);
}
private function onSwfLoaded(e:Event):void
{
mc = loader.content as MovieClip;
mc.stop();
}
}
}
Have you checked to be sure the embedded clip is compiled for the AVM2 (ie. that it targets AS3 and not AS1 or AS2)? An Avm1 swf may cast to a MovieClip without throwing an error, but will not then respond to commands.