views:

3048

answers:

9

In an ActionScript 2 project I can create a new MovieClip, right-click on it on the library and select "Component Definition" to add parameters that can be referenced inside the MovieClip. This parameters can be easily changed in the MovieClips's properties.

Now, I'm working on an ActionScript 3 project but haven't been able to figure out a way to obtain the values passed in those parameters.

I defined a parameter named "textToDisplay" but when I write the following in the Actions for the first frame I get an error:

trace(textToDisplay);

This is the error:

1120: Access of undefined property textToDisplay.

Do you know how to capture the value of that parameter?

Thanks

PS: I'm using Adobe Flash CS3 Professional on Windows XP

A: 

I haven't used this specific functionality, but likely you will need to define a custom class for that MovieClip (just subclass MovieClip) and add that extra variable. Actionscript 3 has moved away from the dynamic nature of actionscript 2, this can be a bit confusing to start with, but in the end it's much more robust.

grapefrukt
+1  A: 

In as3 you have to create an external class file with one or more public var declarations that you will use (you can also use public get/set functions). Google this if you're not sure how.

In your external file, use the [Inspectable] metadata tag just before your var, like this:

package myPackage {
  import flash.display.MovieClip;

  public class MyComponent extends MovieClip {

    [Inspectable]
    public var myFancyComponentParameter:String;

    [Inspectable]
    public var myOtherFancyComponentParameter:int;

  }

}

Then you can open the Component Definition dialog, set the Class field to the name of your external class (including package name), and Flash will automatically create parameters for your component based on your [Inspectable] tags. Or you can create them manually.

Once you've set this up, you can access the component vars in timeline code:

trace("Here's my var: " + myFancyComponentParameter);

Details on the [Inspectable] tag (including data types) are available at the metadata livedocs.

It's also a good idea to set the class name in the Linkage dialog too, if you want your external class to do anything other than hold component values.

I'd also recommend putting code in your external class, rather than in the timeline. It's more extensible that way. If you do this, just remember that your component parameters aren't set until after the INIT event is fired. Here's how to listen for that:

// package and import statements omitted for brevity
public class MyComponent extends MovieClip {

  [Inspectable]
  public var myFancyComponentParameter:String;

  public function MyComponent() {
    // myFancyComponentParameter not set here yet
    trace(myFancyComponentParameter); // prints null
    addEventListener(Event.INIT, onInit);
  }

  public function onInit(e:Event) {
    // now we can use component parameters!
    trace(myFancyComponentParameter); // prints the param value
  }

}
aaaidan
A: 

I do not see an INIT event in the MovieClip class definition and it does not seem to be called.

A: 

I had the same problem - there is no INIT event for a MovieClip - but otherwise this solution works fine. The only way I could see to get around this is to use Event.ENTER_FRAME and remove the listener again the first time the handler is called. My component parameters were accessible from the next frame onwards, but I find it surprising that no official event exists when a movie clip is instantiated.

A: 

There is an ADDED_TO_STAGE event that would work better than the ENTER_FRAME event that steve-mann suggested.

Kevin
+2  A: 

Considering how hard it is to find information about custom component setup I thought i would clear up some aspects of the process based on what I have experienced.

INIT EVENT:

For the most part aaaidan example above is correct with one exception.

addEventListener(Event.INIT, onInit);

should be:

loaderInfo.addEventListener(Event.INIT, onInit);

the loaderInfo property of a DisplayObject refrences a LoaderInfo from which your component gets its parameter settings from. the INIT event is called when it has gotten its data (alternativly you could use the COMPLETE event, which should fire directly after the INIT)

INSPECTABLE METADATA:

when your setting up properties to be accessed using the metadata [Inspectable] tag, you can also define default values using:

 [Inspectable(defaultValue="whatevervalue")]

from what I have experience the parameters seem to have trouble dealing with anything other then a String (and perhaps Numbers), so I would suggest using set functions that take string values and use them to obtain the other values you may want. for example if you want to load a new instance of a specific named class

 [Inspectable(defaultValue="flash.display.Sprite")]
public function set className(value:String):void{
       var ClassReference:Class = getDefinitionByName(value) as Class;
       _class = new ClassReference();
}

in this example if the parameter is set to "flash.display.Sprite" calling "new _class() will create a new Sprite instance.

SETSIZE FUNCTION:

if you want your custom component to resize in a way other then simply stretching the height and width values you need a public setSize function. this function will be called every time you resize your component in flash.

public function setSize(w:Number, h:Number):void{
   _menuWidth = w;
   _menuHeight = h;
}

now this works great when your resizing the component in flash but once you actually publish your swf file you will notice that it switches back to stretching width and height rather then using your setSize function (i dont know why but thats what it does). to fix this, in your onInit function you need to take the width and height, feed them into your setSize, and then reset the scaleX and scaleY values back to 1 :

public function onInit(e:Event):void{
   setSize(width,height);
   scaleX = 1;
   scaleY = 1;
   //add other functions that need to be run once the parameters are loaded
}

(if anyone finds a less messy way of doing this let know)

hope this helps someone get their custom components up and runing.

omg, thanks for the tip on adding the INIT to loaderInfo... i've almost ripped all my hair out
dizy
A: 

In the CS4 10.0.2 release, you can right-click and add component parameters manually again.

Two Things to note:

  1. You WILL still need to wait for loaderInfo Event.INIT before you can reference the custom values (ie: loaderInfo.addEventListener(Event.INIT, initComponent)
  2. You will need to define the parameter on the 1st frame (var paramName) in order to be able to reference it without a compiler error.

Hope this helps you...I know it helped me!

~Greg

A: 

I really think that Flash is absolutely necessary, for example I use some interesting flash components on my blog. I also find some free flash components. I recommend a nice website flashcomponents.net , with a lot of free flash components

juliaflashcomponents
A: 

Hi guys,

Nice article. I have one question tho...or problem even. I dont get the Event.INIT for some reason..

Making a custom component with an external class as document class. In this external class, inside the constructor i add the listener for the INIT...i even place a trace there... First of all the INIT is not being fired and second even that trace is not being fired..

Also when i change the [Inspectable] vars .... and then want to read them in the onInit.... it gives me a huge error: TypeError: Error #1009: Cannot access a property or method of a null object reference. at ctest_fla::MainTimeline/__setProp_px_Sc() at ctest_fla::MainTimeline()

Does someone have a simular problem... I just cant get past it.. have searched everywhere online but no solution.. :( can you guys help me ?

Thnx in Advance

@EDIT: Fixed the problem.... i needed to rightclick movieclip and go to component definition and add a class.

Also a later problem was that my component lost all its number/ int variables when i compiled my swf... Solution was to keep everything a string... and only when i assign it to a numbered typed var i would cast it to a number/int.