Creating buttons in a loop in AS3

In AS2, you were able to use the following technique to create a set of buttons (as always, when I say "buttons" I usually mean MovieClips being used as buttons, as is the case here):

  1. Open a new Flash Actionscript 2.0 file (yes, that's AS2!).
  2. Create a MovieClip symbol: Draw something on the stage (I made a rectangle with a width of 90 and a height of 32), convert it to a MovieClip, then delete that instance from the stage.
  3. Right-click your symbol in the library, and set its linkage identifier to a name of your choice. I'm using "ButtonMC" for a linkage identifier (note: don't put anything in the Class field).
  4. Write code on layer 1, frame 1, resembling the following:
for(var i = 0; i < 5; i++) {
	this.attachMovie("ButtonMC", "btn" + i, i);
	this["btn" + i]._y = 15;
	this["btn" + i]._x = i * 100 + 15;
}
btn0._y += 20; //affect one certain button by name

This block of code not only creates five buttons and adds them to the display, but also gives you five new instance names that you can use in your subsequent code to refer to them by: btn0, btn1, btn2, btn3, and btn4. So, notice that after the for loop, you are able to affect just one of the buttons by directly using the name btn0. You are able to use the name btn0 like any other instance name, as though you had set it in the properties panel.

This is no longer possible in AS3. At least not exactly. So a lot of people who know AS2 are naturally perplexed, when they begin to learn AS3, that the above scenario isn't possible anymore. That is, although you can dynamically add your buttons to the stage by giving the symbol a class name, you can't give each one an instance name that you can use directly, as you could in AS2. However, you can come close. I will outline the "close" techniques, and then show you an even better approach using arrays.

Now let's switch to AS3, and work with a fla file of that type. Open a new Flash Actionscript 3.0 file. Create a similar MovieClip symbol, or just copy the same one over from the AS2 file. Instead of a linkage name of "ButtonMC," now it should have a Class name of "ButtonMC." We would use "new ButtonMC()" to create an instance programmatically, and optionally set that new instance equal to a variable name. But now there is no way in the loop to create a set of variable names like the instance names from the AS2 version. Here is the first way that we are able to closely approximate it, though:

for(var i = 0; i < 5; i++) {
	this["btn" + i] = new ButtonMC(); 
	this["btn" + i].y = 15;
	this["btn" + i].x = i * 100 + 15;
	addChild(this["btn" + i])
}
this.btn0.y += 20; //affect one certain button by name

One disadvantage here is that since you create the variable with array access notation, you can't give the variable a type. Another disadvantage is that in the subsequent code, you must use the "this" keyword every time. Using btn0 by itself won't work. The only reason the whole thing works at all is because the main timeline is basically a MovieClip, and MovieClip is a dynamic class (So this whole scenario would not work if you were writing your code in a document class that extended Sprite instead of MovieClip. And in a document class that extended MovieClip, the document class would have to be declared dynamic, also).

Here is the second technique:

for(var i = 0; i < 5; i++) {
	var btn:ButtonMC = new ButtonMC();
	btn.y = 15;
	btn.x = i * 100 + 15;
	btn.name = "btn" + i;
	addChild(btn);
}
getChildByName("btn0").y += 20; //affect one certain button by name

In this approach, a new instance of ButtonMC is set equal to a variable. However, the same variable is reused in subsequent iterations of the loop. So after the loop runs, this variable points only to the last object created, or btn4. So this variable isn't of any use for our purpose here. However, each button, as it was generated, was given an name. The name property of display objects is just simply a string value. It is not an instance name. But as you can see, we are able to use the method getChildByName(), which is a method of the DisplayObjectContainer class, to refer to a specific button. The disadvantages here are:

  1. Every button must be on the container's display list. In the above, if the addChlid() had not been performed, we would not be able to address a specific button.
  2. It's a lot of extra typing to have to use getChildByName("btn0") every time.

The two techniques outlined above, while you can use them, really leave a lot to be desired, at least in my opinion. There just is no longer any way to create a series of variable names in a loop and use the loop counter to increment the variable name. At least, if there is, I haven't found it yet. So, that's the bad news. But the good news is that there's a better way that is so good, you won't even miss the old AS2 way! It's called an array. And here is the array technique:

var btn:Array = new Array();
for(var i = 0; i < 5; i++) {
	var button:ButtonMC = new ButtonMC();
	button.y = 15;
	button.x = i * 100 + 15;
	addChild(button);
	btn.push(button);
}
btn[0].y += 20; //affect one certain button by name

This creates an array named btn. Now, in the loop, I've chosen another name for the temporary variable: "button." When you create an array, you basically get a series of variable names that you can use by just supplying the index in the brackets. You can use these variable names as though they were instance names of the buttons themselves. Notice that in the line after the loop, that offsets the first button, we can just use "btn[0]." So the only real disadvantage between this and the AS2 version is that you have to type brackets. Big deal!

But putting buttons in an array has other advantages that the AS2 technique can't match. We will explore those advantages in the remainder of this article, as we leave the AS2 technique behind in favor of using arrays.

I should note, though, that even in AS2 it was possible to put buttons in an array, and use the technique outlined above. So this isn't completely an AS2 vs. AS3 thing. It's more an issue of one technique vs. another. In AS2, the "buttons in an array" technique was already superior to the "series of numbered instance names" for those who cared to use it. But now that in AS3 that latter technique is no longer an option, it just becomes that much more important to learn the array technique.

It has always seemed to me that those who want to hang onto names in programming just haven't (yet!) learned the techniques I'm going to outline in this article.

we are not worthy....

Great post... I am especially grateful that you give other options to accomplish the task. Extremely thorough. Thanks

-Aku

Big help

Thanks so much for posting this. It was of great help to me.