13.4 Issues with Nested Assets

 <  Day Day Up  >  

Movie clip symbols can contain other nested movie clips, text fields, or components (i.e., elements attached to the clip symbol during authoring or at runtime). To access and use these nested assets, we must sidestep two issues.

13.4.1 Properties and Methods of Nested Assets Initially Undefined

The Flash Player takes an "outside-in" approach to component and movie clip initialization. When initializing a movie clip hierarchy in a movie, the Flash Player starts with the outermost clip in the hierarchy, defines its custom properties and methods, then moves on to its child clips, defines their custom properties and methods, and so on. As a result, immediately after a clip is constructed , it can see its parent's custom methods and properties, but it cannot see its children's custom methods and properties.

For example, consider a movie clip symbol, ChatRoomSymbol , that represents a chat room. It contains the following component instances:


outgoing

A TextInput component for outgoing messages


incoming

A TextArea component for incoming messages


userList

A List component for the list of users in the room

Suppose we use a ChatRoomSymbol instance via composition in a class, ChatRoom , as follows :

 class ChatRoom {   private static var chatroomID:Number = 0;   private var chat_mc:MovieClip;   public function ChatRoom (target:MovieClip, depth:Number) {     // Create clip instance.     chat_mc = target.attachMovie("ChatRoomSymbol",                                   "chatroom" + ChatRoom.chatroomID++,                                   depth);     chat_mc.userList.dataProvider = [{label:"Colin", data:"User1"},                  {label:"Derek", data:"User2"},                  {label:"James", data:"User3"}];   } } 

The ChatRoom constructor creates an instance of the ChatRoomSymbol movie clip symbol and stores it in the property chat_mc . (By now, you should know that it actually stores the ActionScript object representation of the ChatRoomSymbol instance, so I'll no longer make the distinction.) The constructor then attempts to populate the nested userList List component by assigning a value to its dataProvider property:

 chat_mc.userList.dataProvider = [{label:"Colin", data:"User1"},              {label:"Derek", data:"User2"},              {label:"James", data:"User3"}]; 

But the assignment has no effect because the userList component's properties and methods are not yet functional! To overcome this problem, we must use setInterval( ) to poll the userList component until its custom properties and methods are defined. Once we detect the existence of a single userList method, we can be sure that all of its properties and methods are available. In fact, we can also be sure that every other nested component is, likewise, ready for use. By the time a single frame passes , the custom properties and methods of all nested assets will be initialized .

The following new code for the ChatRoom class shows how to poll for the existence of a userList List component instance's method. The new code uses an init( ) method to initialize nested components. The init( ) method is called by the function passed to setInterval( ) as soon as the userList.addItem( ) method is defined. Notice that the function passed to setInterval( ) is, itself, passed a reference to the current object, this . This technique allows the function passed to setInterval( ) to invoke the init( ) method on the current object. Without the reference to this , the nested function called by setInterval( ) would have no access to the current object and could not invoke init( ) .

 class ChatRoom {   private static var chatroomID:Number = 0;   private var chat_mc:MovieClip;   public function ChatRoom (target:MovieClip, depth:Number) {     // Create clip instance.     chat_mc = target.attachMovie("ChatRoomSymbol",                                   "chatroom" + ChatRoom.chatroomID++,                                   depth);  // Wait until nested clips are initialized before   // performing any operations on them  .  var initInt = setInterval(function (cr:ChatRoom):Void {   if (cr.chat_mc.userList.addItem != undefined) {   cr.init( );   clearInterval(initInt);   }   }, 10, this);  }  public function init ( ):Void {   // Hardcode some dummy data for this example  .  setUserList([{label:"Colin", data:"User1"}  ,  {label:"Derek", data:"User2"}  ,  {label:"James", data:"User3"}]);   }   public function setUserList (list:Array):Void {   chat_mc.userList.dataProvider = list;   }  } 

When you want to access the custom properties and methods of an asset nested in a movie clip immediately after creating that clip, you should use the preceding setInterval( ) technique. If, however, you want to use a native property or method of the MovieClip class (e.g., gotoAndPlay( ) ), then you do not have to use setInterval( ) . Native properties and methods are immediately available on all nested assets.

13.4.2 Nested Assets Not Automatically Recognized by Compiler

Assets nested in a movie clip symbol are not automatically available to a corresponding MovieClip subclass as instance properties. That is, a MovieClip subclass cannot refer to assets nested inside its associated movie clip symbol unless the subclass explicitly declares those assets as instance properties.

For example, consider a LoginSymbol movie clip symbol that contains two text fields, userName and password . The LoginSymbol 's corresponding MovieClip subclass is Login . The Login class wants to set the default contents of the userName and password text fields. If we use the following Login class code:

 class Login extends MovieClip {   public function Login ( ) {     userName.text = "Enter your name.";     password.text = "Enter your password.";   } } 

the compiler generates the following errors:

 There is no property with the name 'userName'.          userName.text = "Enter your name."; There is no property with the name 'password'.          password.text = "Enter your password."; 

We know that the LoginSymbol movie clip symbol contains the required text fields, but the compiler doesn't have any way of knowing. The compiler bases its type checking on the Login class definition, not the contents of the LoginSymbol movie clip symbol. To work around this problem, we simply declare the userName and password text fields as instance properties, like this:

 class Login extends MovieClip {   public var userName:TextField;  // Declare   userName   public var password:TextField;  // Declare   password   public function Login ( ) {     userName.text = "Enter your name.";     password.text = "Enter your password.";   } } 

 <  Day Day Up  >  


Essential ActionScript 2.0
Essential ActionScript 2.0
ISBN: 0596006527
EAN: 2147483647
Year: 2004
Pages: 177
Authors: Colin Moock

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net