Could anyone tell me whats wrong with this code? I'm attempting to rotate a button in action script 3 and i keep getting the error:
ArgumentError: Error #2025: The supplied DisplayObject must be a child
of the caller. at flash.display::DisplayObjectContainer/removeChild()
at
distributor_app_fla::MainTimeline/NewChartOptionsReturn()[distributor_app_fla.MainTimeline::frame1:218]
at
distributor_app_fla::MainTimeline/ClickNewChartOptions()[distributor_app_fla.MainTimeline::frame1:101]
I've already Googled the error and everything i read told me to remove the child then re-add it to the frame but it continues to break at the same spot.
code:
//defined
var btnNewChartOptions:NewChartOptions = new NewChartOptions();
btnNewChartOptions.y = 279;
btnNewChartOptions.x = 439;
//created
function NewChartDown():String
{
btnNewChartOptions.addEventListener(MouseEvent.CLICK, ClickNewChartOptions);
btnNewChartOptions.alpha = 0;
addChild(btnNewChartOptions);
var NewChartOptionsTween:Tween = new Tween(btnNewChartOptions, "alpha", Strong.easeOut, 0, 1, 1, true);
return "NewChartSelected";
}
//actual code on button
function NewChartOptionsDown():String
{
rightGrayOut.alpha = 0;
addChild(rightGrayOut);
var grayOutTween:Tween = new Tween(rightGrayOut, "alpha", Strong.easeOut, 0, 1, 1, true);
var rotateTween:Tween = new Tween(btnNewChartOptions, "rotation", Strong.easeOut, 0, 180, 1, true);
return "NewChartOptions";
}
any help is appreciated!
There will be no need to remove and re-add the object because it is either present and available to the method or not, meaning if it were available to the method for removal then it would also be available for addressing and manipulation. This sounds a whole lot like a scope/visibility issue.
This code is on frame 1 on the timeline, which means that it should be able to address anything that's directly on the stage or assigned to a variable that is in the same scope at the time the function is run. (In the _root scope if this was AS2, like the methods on frame 1)
Is btnNewChartOptions inside another DisplayObject, like a sprite you use to hold all your buttons or something, as opposed to sitting directly on the stage? Maybe you can describe the object heirarchy you are trying to address as well as how the button gets attached to the stage (e.g. instantiated and attached at runtime or placed on the stage in a keyframe).
Can you provide the error that was being thrown before the add and remove fix was attempted?
If looks like to me the object has not been added yet to the display list.
// replace the following lines
removeChild(btnNewChartOptions);
addChild(btnNewChartOptions);
// with
if( !this.contains( btnNewChartOptions ) ){
return "";
}
[EDIT]
Your code.
//var created
var btnNewChartOptions:NewChartOptions = new NewChartOptions();
btnNewChartOptions.y = 279;
btnNewChartOptions.x = 439;
//button code clicked that creates button
function NewChartDown():String {
btnNewChartOptions.addEventListener(MouseEvent.CLICK, ClickNewChartOptions);
btnNewChartOptions.alpha = 0;
addChild(btnNewChartOptions);
var NewChartOptionsTween:Tween = new Tween(btnNewChartOptions, "alpha", Strong.easeOut, 0, 1, 1, true);
return "NewChartSelected";
}
//function for button
function NewChartOptionsDown():String {
rightGrayOut.alpha = 0;
addChild(rightGrayOut);
var grayOutTween:Tween = new Tween(rightGrayOut, "alpha", Strong.easeOut, 0, 1, 1, true);
var rotateTween:Tween = new Tween(btnNewChartOptions, "rotation", Strong.easeOut, 0, 180, 1, true);
return "NewChartOptions";
}
In your code you provided you are only doing addChild(btnNewChartOptions); in the NewChartDown function.
So that tells me that NewChartOptionsDown can not be called until NewChartDown has been called first. Because the btnNewChartOptions has never been added.
What you can do is move addChild(btnNewChartOptions); outside of the function.
//var created
var btnNewChartOptions:NewChartOptions = new NewChartOptions();
btnNewChartOptions.y = 279;
btnNewChartOptions.x = 439;
addChild(btnNewChartOptions);
Related
I'm trying to create a simple slideshow of 3 images going from left to right.
I want to check if the last image is on stage ( so the image3.x = 0 ) in order to start the new Tween.
I thought it would be something a simple as the following code, but that doesn't seem to work.
function Start() {
if(image3.x == 0){
var myTween:Tween = new Tween(image, "x", None.easeNone, -140, 640, 10, true);
}
}
stage.addEventListener(Event.ENTER_FRAME, Start);
Split the original Tween in two parts, from -140 to 0 and from 0 to 640.
var tween:Tween = new Tween(image, "x", None.easeNone, -140, 0, 10, true);
Wait for it to finish:
tween.addEventListener(TweenEvent.MOTION_FINISH, onZeroReached);
Then do the second part plus whatever else you want to do:
function onZeroReached(te:TweenEvent):void
{
tween = new Tween(image, "x", None.easeNone, 0, 640, 10, true);
// do additional stuff here
}
code untested
My problem looks like: I have five buttons and four of them are loading four different swf galleries into the main swf, the last one unloads all galleries. Each of them has exactly the same code, the only differeces are the locations of jpg files and swf files. Also each o them has the listeners ADDTOSTAGE and REMOVEFROMSTAGE, because i'm using the stage inside the gallery/swfs.
So when I enter the menu and load the first swf i don't get any output errors, when I click the btn_back he unloads the swf properly with no errors. And so on but only when i load only one gallery.
But when I, after loading the first gallery, want to click on another button and load second gallery then i got this error in output, so many times as many pictures are loaded inside the loaded swf/gallery:
TypeError: Error #1009: Nie można uzyskać dostępu do właściwości lub metody dla odniesienia do obiektu null.
at DocObject/resizeMyDoc()
at DocObject/onResizeDoc()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at flash.display::Stage/dispatchEvent()
at Miniaturka/onAddedToStage()
at flash.display::DisplayObjectContainer/addChild()
at Miniaturki/callback()
at Function/http://adobe.com/AS3/2006/builtin::apply()
at Miniaturka/onLoadComplete()
So my conclusion is that the problem is not inside the loaded swf but in the code of loading and unloading code of the mine swf. The only solution that I can find is: that when I click the second button the code should first unload the current swf, and when the unload is complete then immidietly load the another one. But I don't know how to write it. Can anyone help? So here is the code.
import flash.events.MouseEvent;
import fl.transitions.Tween;
import fl.transitions.easing.*;
import fl.transitions.TweenEvent;
import flash.display.Loader;
var _mainLoader:Loader;
var _currentContent:DisplayObject;
var url:URLRequest;
var loaded:Boolean = false;
var a:Array = new Array(s1_1_arch, s1_2_arch, s1_3_arch, s1_4_arch);
var swfList:Array = ["A0101.swf", "A0102.swf", "A0103.swf"];
//Initiate Loader, do it only once
function initiateLoader():void {
_mainLoader = new Loader();
_mainLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
}
function loadGallery(path:String):void {
//Check if content previously loaded, unload it
if (_currentContent != null) {
removeChild(_currentContent);
_currentContent = null;
_mainLoader.unloadAndStop();
}
//Now load another one
_mainLoader.load(new URLRequest[1]);
}
function onComplete(e:Event):void {
_currentContent = _mainLoader.content;
//Add root DisplayObject of the loaded content to the display list
stage.addChild(_currentContent);
}
function samClick(e:MouseEvent):void
{
switch (e.target)
{
case s1_1_arch :
break;
case s1_2_arch :
break;
case s1_3_arch :
break;
case s1_4_arch :
break;
}
}
function samOver(e:MouseEvent):void{
switch (e.target)
{
case s1_1_arch : var sam1Ou:Tween = new Tween(s1_1_arch, "alpha", Strong.easeOut, 1, 0.2, 0.5, true);
break;
case s1_2_arch : var sam2Ou:Tween = new Tween(s1_2_arch, "alpha", Strong.easeOut, 1, 0.2, 0.5, true);
break;
case s1_3_arch : var sam3Ou:Tween = new Tween(s1_3_arch, "alpha", Strong.easeOut, 1, 0.2, 0.5, true);
break;
case s1_4_arch : var sam4Ou:Tween = new Tween(s1_4_arch, "alpha", Strong.easeOut, 1, 0.2, 0.5, true);
break;
}
}
function samOut(e:MouseEvent):void{
switch (e.target)
{
case s1_1_arch : var sam1Ou:Tween = new Tween(s1_1_arch, "alpha", Strong.easeOut, 0.2, 1, 0.5, true);
break;
case s1_2_arch : var sam2Ou:Tween = new Tween(s1_2_arch, "alpha", Strong.easeOut, 0.2, 1, 0.5, true);
break;
case s1_3_arch : var sam3Ou:Tween = new Tween(s1_3_arch, "alpha", Strong.easeOut, 0.2, 1, 0.5, true);
break;
case s1_4_arch : var sam4Ou:Tween = new Tween(s1_4_arch, "alpha", Strong.easeOut, 0.2, 1, 0.5, true);
break;
}
}
for (var i:Number = 0; i < 4; i++)
{
a[i].addEventListener(MouseEvent.CLICK, samClick);
a[i].addEventListener(MouseEvent.MOUSE_OVER, samOver);
a[i].addEventListener(MouseEvent.MOUSE_OUT, samOut);
}
Just to add...
For something like this you are better of having all code in one place. A class file will save you other frustrations later on if you're still new. Just control all elements from one place. Also consider what Nicolas Siver said in his answer..
Just a quick guide on how to setup class file. If you save as Main.as and attach to your FLA then you can paste in your timeline code here.
package
{
//IMPORTS go here
//Declare your Class (name of .as file)
public class Main extends MovieClip
{
//VARS go here
//Declare main function of your Class (must have same name as Class (.as file)
public function Main()
{
// Your main program code go here
//Something(); //example: run a function called Something
}
public function Something();
{
// Do something code
}
} //End of Class
} //End of Package
You are on the right way. But you have many problems in your code, most of your switches are redundant. By default, all galleries, that you are loading, will be loaded in child ApplicationDomains, so they are suitable for garbage collection.
If you will use single Loader it will be easier for you to manage it, and load one section in time.
//Pseudo code
Create main loader (with onComplete event handler);
Create a function for loading content, and call it.
Check if previous load operation was successful (use your flag `loaded`), if Yes - unload previous content, remove previous content from the display list;
Load new content;
After loading is completed, add content to the main display list holder, designed to show gallery content.
Also I would recommend to use TweenLite, It's also more developer friendly.
Here for you several utility functions that will help you accomplish your task:
private var _mainLoader:Loader;
private var _currentContent:DisplayObject;
//Initiate Loader, do it only once
private function initiateLoader():void {
_mainLoader = new Loader();
_mainLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
}
private function loadGallery(path:String):void {
//Check if content previously loaded, unload it
if (_currentContent != null) {
removeChild(_currentContent);
_currentContent = null;
_mainLoader.unloadAndStop();
}
//Now load another one
_mainLoader.load(new URLRequest(path));
}
private function onComplete(e:Event):void {
_currentContent = _mainLoader.content;
//Add root DisplayObject of the loaded content to the display list
addChild(_currentContent);
}
More concrete realisation, you could use it in your frame, but don't forget to do all imports, and create all necessary display object on the scene:
//Self explanatory
var currentContent:DisplayObject;
//Initiate Loader
var mainLoader:Loader = new Loader();
mainLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
//Create some MovieClip and give it a name, you will place loaded content there, ex: contentHolder
//Add buttons in one container (MovieClip) and give it name, ex: buttonHolder
//Give buttons some names, ex: s1Arch, s2Arch, s3Arch
//Map our buttons to external links and prepare for mouse events
var links:Object = {"s1Arch": "A0101.swf", "s2Arch": "A0102.swf", "s3Arch": "A0103.swf"};
//Register listeners, you could do it in cycle
s1Arch.addEventListener(MouseEvent.CLICK, onClickButton);
s2Arch.addEventListener(MouseEvent.CLICK, onClickButton);
s3Arch.addEventListener(MouseEvent.CLICK, onClickButton);
//Mouse events, using events bubbling
buttonHolder.addEventListener(MouseEvent.CLICK, onClickButton);
function loadGallery(path:String):void {
//Check if content previously loaded, unload it
if (currentContent != null) {
contentHolder.removeChild(currentContent);
currentContent = null;
mainLoader.unloadAndStop();
}
//Now load another one
mainLoader.load(new URLRequest(path));
}
function onClickButton(e:MouseEvent):void {
//Explanation step-by-step
//Clicked button
var button: DisplayObject = DisplayObject(e.currentTarget);
//Path to the external file
var path: String = links[button.name];
//Utility function will handle another stuff
loadGallery(path);
}
function onComplete(e:Event):void {
currentContent = mainLoader.content;
//Add root DisplayObject of the loaded content to the display list
contentHolder.addChild(currentContent);
}
I am a beginner with using AS3 and as3isolib. I am trying to add some MC from the fla library into an isoGrid object. I tried to use addChild() method of the IsoGrid class but it gave me an error saying: 1067: Implicit coercion of a value of type [MovieClip Name] to an unrelated type as3isolib.data:INode. Which I think wants me to use the node class.
Any idea how to do such a thing?
Thank you in advance.
as3isolib use it's own display list like rendering tree, add all nodes in this tree must implements as3isolib.data:INode. There are two possibility to add flash native display objects to the IsoScene:
Take a look on this small tutorial:
//create IsoView, IsoScene and IsoGrid - default from as3isolib
var view:IsoView = new IsoView();
view.setSize(stage.stageWidth, stage.stageHeight);
addChild(view);
var scene:IsoScene = new IsoScene();
view.addScene(scene);
var grid:IsoGrid = new IsoGrid({cellSize:32});
grid.setGridSize(800, 600);
grid.stroke = new Stroke(0, 0x576F33);
grid.render();
//create iso box, just for demo
var obj:IsoBox = new IsoBox();
obj.setSize(32, 32, 64);
obj.moveTo(5*32, 5*32, 1);
//first possiblity to add flash.display.Shape to the iso scene - using IsoSprite.sprites
var isoSprite:IsoSprite = new IsoSprite();
isoSprite.moveTo(5*32, 7*32, 1);
var shape1:Shape = new Shape();
shape1.graphics.beginFill(0xFF0000, 1);
shape1.graphics.drawRect(0, 0, 32, 32);
isoSprite.sprites = [shape1];
//second possiblity to add flash.display.Shape to the iso scene - using IsoDisplayObject.container
var isoObj:IsoDisplayObject = new IsoDisplayObject();
isoObj.moveTo(7*32, 7*32, 1);
var shape2:Shape = new Shape();
shape2.graphics.beginFill(0x0000FF, 1);
shape2.graphics.drawRect(0, 0, 32, 32);
isoObj.container.addChild(shape2);
//add all objects to the scene and render all
scene.addChild(grid);
scene.addChild(obj);
scene.addChild(isoSprite);
scene.addChild(isoObj);
scene.render();
I am having huge problems with AS3 and the tweening class. It just stops for no apparent reason...
My code is a menu of side panels that slide in-and-out when the user clicks the tabs.
It looks as follows:
var mainContent1X:Tween = new Tween(MainContent1, "x", Strong.easeOut, MainContent1.x, 325, 1, true);
var MainContent2X:Tween = new Tween(MainContent2, "x", Strong.easeOut, MainContent2.x, 1750, 1, true);
var mainContent3X:Tween = new Tween(MainContent3, "x", Strong.easeOut, MainContent3.x, 1750, 1, true);
var MainContent4X:Tween = new Tween(MainContent4, "x", Strong.easeOut, MainContent4.x, 1750, 1, true);
var mainContent5X:Tween = new Tween(MainContent5, "x", Strong.easeOut, MainContent5.x, 1750, 1, true);
var MainContent6X:Tween = new Tween(MainContent6, "x", Strong.easeOut, MainContent6.x, 1750, 1, true);
It just stops for no reason at all like the code isn't being executed. Sometimes only one tween happens and the others don't. Sometimes it works the way I want it to!!! I can't figure out why this is happening, I am relatively new to AS3, I'll appreciate any help.
Regards
Luben
I assume its a lifetime problem of your variables. If your tween variables are only in local scope of a function, at the end of that function they are lost and so your Tweens.
Make them class variables or even better, use Tweener.
Thanks Daniel,
I declared the variables outside the function and all is fine. It seems that the garbage collector was clearing them at the wrong time. The code looks as follows now:
var mainContent1X:Tween;
function name() {
mainContent1X = new Tween(MainContent1, "x", Strong.easeOut, MainContent1.x, 325, 1, true);
...
}
I'll look into Tweener/TweenMax although I'm hesitant about using 3rd party software.
Thanks again,
Luben
i'm trying to duplicate a swf loaded using greensocks LoaderMax but i don't seem to be able to
i'm using the following code:
private var _assetCache : Dictionary;
public function getAssetById(assetId:String):DisplayObject
{
var asset:DisplayObject;
if (!_assetCache[assetId])
{
_assetCache[assetId] = LoaderMax.getContent(assetId).rawContent;
}
asset = _assetCache[assetId];
// duplicate bitmap
if (asset is Bitmap)
{
var bmd:BitmapData = new BitmapData(asset.width, asset.height, true, 0);
return new Bitmap(bmd, "auto", true);
}
// otherwise return
return SpriteUtils.duplicateDisplayObject(asset);
//return asset; // if previous line is commented out, this works well but there will be only a single copy of the loaded swf, kinda negating the use of a cache
}
and this is SpriteUtils.duplicateDisplayObject(asset) (taken from this
static public function duplicateDisplayObject(target:DisplayObject, autoAdd:Boolean = false):DisplayObject
{
// create duplicate
var targetClass:Class = Object(target).constructor;
var duplicate:DisplayObject = new targetClass();
trace(duplicate, duplicate.height); // traces [MovieClip, 0]
// duplicate properties
duplicate.transform = target.transform;
duplicate.filters = target.filters;
duplicate.cacheAsBitmap = target.cacheAsBitmap;
duplicate.opaqueBackground = target.opaqueBackground;
if (target.scale9Grid)
{
var rect:Rectangle = target.scale9Grid;
// WAS Flash 9 bug where returned scale9Grid is 20x larger than assigned
// rect.x /= 20, rect.y /= 20, rect.width /= 20, rect.height /= 20;
duplicate.scale9Grid = rect;
}
// add to target parent's display list
// if autoAdd was provided as true
if (autoAdd && target.parent)
{
target.parent.addChild(duplicate);
}
return duplicate;
}
if i simply return the asset from _assetCache (which is a dictionary) without duplicating it, it works and traces as a MovieClip but when i try to duplicate it, even though the traces tell me that the duplicate is a movieclip. Note the clip being loaded is a simple vector graphic on the stage of the root of the timeline
thanks in advance
obie
I don't think simply calling the constructor will work.
Try doing this (I've assumed certain previous knowledge since you're able to get rawContent above):
1) Load the data in using DataLoader in binary mode.... in the context of LoaderMax it would be like: swfLoader = new LoaderMax({name: "swfLoader", onProgress:swfProgressHandler, onChildComplete: swfLoaded, auditSize:false, maxConnections: 2}); swfLoader.append(new DataLoader(url, {format: 'binary'})); (the main point is to use DataLoader with format='binary')
2) Upon complete, store the ByteArray which this returns into your dictionary. The first part of your above code will basically be unchanged, though the bytearray might be in content rather than rawContent
3) Whenever you need a duplicate copy, use Loader.loadBytes() on the ByteArray. i.e. var ldr:Loader = new Loader(); ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, swfReallyLoaded); ldr.loadBytes(_assetCache[assetId]);
As with all loading, you might need to set a LoaderContext, and if in AIR- allowLoadBytesCodeExecution = true; allowCodeImport = true;