AS3 Dropdown Menu with Reusable Classes

Creating the MenuButton Class
Now go to File / New... and choose New Actionscript (AS) file. Type in (or copy and paste) the following basic class outline:
package {
import flash.display.*;
import flash.events.*;
public class MenuButton extends Sprite {
public function MenuButton() {
}
}
}
Immediately save this file to the same folder location as the fla file. You may have to browse your system's folder tree again to get there, as Flash seems to remember the last location of fla and as files separately (sometimes I wish it didn't!). But once you've saved a file of each kind there, you're good to go after that. The only thing to note here is that our class extends the Sprite class. As such, it inherits from the DisplayObjectContainer class, so it can contain other objects. In fact, the Sprite class is like the MovieClip class, without all the timeline methods and properties like gotoAndPlay, currentFrame, etc. All of those things are excess baggage if you know for a fact you won't be using them, and we won't be in this case. We won't be linking to a library symbol--this class will draw its own graphics using code. We do get all of the other properties of MovieClips though, like x, y, rotation, width, height, alpha, and a host of others, so you are still on familiar ground if you did a lot of AS2. It's not that different at its heart.
Let's get something displaying on the screen
What I like to do right off the bat is to get something on the screen I can see immediately. I like visual feedback a lot--I like to see what I'm building as I go along. So in the fla file, let's write these two lines on frame 1 of the main timeline:
var btn:MenuButton = new MenuButton();
addChild(btn);
Before we test this, though, let's do a little more work on the class, so that it produces something we can see. I do already know that the MenuButton class is going to have a draw() method, as I have a scheme already in mind where whenever I update a property, I can just immediately call the draw() method so that the button will redraw and update itself. But for now, the draw() method will just create the background shape we discussed earlier, and add it to the display list. Also, let's go ahead and set buttonMode to true (for the hand cursor to show up). Also, I already know ahead of time that I am going to want to set mouseChildren = false, because later there will be a dynamic textbox in the mix, and if you don't set mouseChildren to false, the hand cursor won't show over the textbox. Setting these two properties is something you just get used to doing when you make Sprite buttons with dynamic text boxes for their labels. So here's the revised class that sets those two properties I just mentioned in the constructor function, and also calls a brand new freshly written draw() method that just draws a rectangle shape and adds it to the display:
package {
import flash.display.*;
import flash.events.*;
public class MenuButton extends Sprite {
public function MenuButton() {
buttonMode = true;
mouseChildren = false;
draw();
}
private function draw():void {
//background shape:
var bg:Shape = new Shape();
bg.graphics.beginFill(0xFFCC00);
bg.graphics.drawRect(0, 0, 150, 30);
bg.graphics.endFill();
addChild(bg);
}
}
}
In the above, just to get something I can see and run immediately, I have hard-coded some of the values that will later get replaced with dynamic variables instead, like the width and height of the rectangle that is drawn, and its color. Save the class file (Ctrl-S), test the movie (Ctrl-ENTER), and you should see a rectangle in the upper left hand corner of the screen that gives you a hand cursor when you hover it with your mouse. We've got a long way to go, but it's a cool beginning. We know that our class is being instantiated (that means a new instance is being made, or constructed), and we are getting mouse feedback from it.
A brief aside about classes (for those new to them)
Classes are an absolutely fantastic way to write code if you want to make a template for some kind of object and stamp out a LOT of copies, or if you just want to encapsulate a self-contained block of code. If you are at all shaky about what classes are or what they can do, try this short experiment. In the fla file, let's make more instances of the class we just made. You will need to modify the y value of each one so that they are not stacked up on each other, but you will see how easy it is to make more instances with just a few lines of code. Change the code on frame 1 of the fla file so that it says:
var btn:MenuButton = new MenuButton();
addChild(btn);
var btn2:MenuButton = new MenuButton();
addChild(btn2);
var btn3:MenuButton = new MenuButton();
addChild(btn3);
btn2.y = 40;
btn3.y = 80;
Now you can see that there are three instances of our class created and displayed to the screen. Each one has its own copy of the constructor function, and each one has its own copy of the draw() method so that it can draw a rectangle to the screen (which it did). The instances of the class are called objects, and they all occupy their own space in your computer's memory, and they are each a separate little bundle of all the properties and methods that we have written into the class file, but also all the ones that they've inherited from the Sprite class. Case in point: each one got an inherited y property that we were able to set, so that they could be spread out on the display and not stack up visually. Another case in point: each one got its own copy of the buttonMode property so that we could set it to true and get a hand cursor. Each one remembers not only its own property names, but whatever value was last set for each property. You could have just as easily set buttonMode = false for one of those if you wanted, for example. So you can see the power of extending classes. We get all the existing properties and methods of the Sprite class to manipulate at will, and we get to choose to add whatever custom ones of our own we want! Also, with just one class file, we can crank out as many copies as we want, and manipulate the properties and methods of each one independently of the others. From just ONE class file, comes however many copies (objects) we care to create!
The constructor of a class is the special function with the same name as the class, and it is always designated public. This function runs when outside code uses the new keyword to make a new instance of the class. So the constructor is the place to put initialization code, because it conveniently only runs once, when an object is created (or instantiated) from the outside, or controlling code. Other public functions can be called repeatedly from the outside after the object is made, but the constructor just runs once for each object created from a class.
Now that we're all on the same page...
This ability to crank out as many copies of the same class as we want will come in very handy. Each "copy" (object, or instance) of the MenuButton class will thus be able to be configured with a text label, so that it can display text of its own. Later, each one can have a different background color if we want, each one can be a different size, have a different font, and all the things I talked about on the previous page. Once you understand the basic, fairly simple concept of classes and objects, you are well along to putting it all to good use, because the more complex stuff isn't really so complex after all. What looks complex is sometimes just a bunch of simple stuff connected together!
Let's move ahead and start adding the properties I mentioned on the last page. Now, by convention, private properties in a class are sometimes preceded with an underscore (at the whim of the programmer, but like most conventions, it's a good one), and we're going to be using a lot of "setter" functions in this class, and that's when the use of underscores becomes really valuable. I'll explain the use of "setter" functions later on, but for now, let's just add all those private variables to a variables list in the class. I gave a lot of thought to what I might want for default values, as well. So the constructor function has a parameter list with eight items (which is really long!) but none of them is required because they all have default values. Then I reasoned what would be the most natural ordering of all of these parameters. Anyway, here is what I came up with:
package {
import flash.display.*;
import flash.events.*;
public class MenuButton extends Sprite {
private var _label:String;
private var _fontName:String;
private var _fontSize:int;
private var _fontColor:uint;
private var _embedFonts:Boolean;
private var _bgColor:uint;
private var _width:Number;
private var _height:Number;
public function MenuButton(label:String = "Click Here",
fontName:String = "Arial",
fontSize:int = 14,
fontColor:uint = 0x000000,
embedFonts:Boolean = false,
bgColor:uint = 0xFFCC00,
width:Number = 150,
height:Number = 30) {
_label = label;
_fontName = fontName;
_fontSize = fontSize;
_fontColor = fontColor;
_embedFonts = embedFonts;
_bgColor = bgColor;
_width = width;
_height = height;
buttonMode = true;
mouseChildren = false;
draw();
}
private function draw():void {
//background shape:
var bg:Shape = new Shape();
bg.graphics.beginFill(0xFFCC00);
bg.graphics.drawRect(0, 0, 150, 30);
bg.graphics.endFill();
addChild(bg);
}
}
}
That may seem like a lot to take in. But really it's just a matter of declaring eight private variables, all with underscores in front of them. In the constructor all eight of them are given values straight from the parameters list. Each parameter in the list has a default value after the equals sign. The ability to put an equals sign and a value after it in your parameters list is really cool, because it allows you to make optional parameters that the user of the class can either supply, or not. If no arguments are supplied, the default values are used instead. So here's how it works: when outside code makes a new instance of our class, if no arguments are supplied to the constructor, as in:
var btn:MenuButton = new MenuButton();
Then what will be constructed is a button that says "Click Here" on its face, in an Arial font, size 14, with black text, no embedded fonts, a background color of orange, a width of 150 and a height of 30. However, someone might also supply just a first argument, like so:
var btn:MenuButton = new MenuButton("My first menu button");
In this case, what they get is a button with different text than "Click Here" (which was the default), but with all the remaining parameters still using the default. That's why I put some thought into the order, to make it as natural as possible. If someone wants to supply the fourth argument, for example, then they are also stuck with supplying the first three.
Of course, all of this doesn't work just yet, we still have yet to program it all. Right now if you test the movie, the class will do exactly what it was already doing, as we haven't affected the behavior at all with these changes. We just simply made a list of eight parameters, recorded them into private variables, made them all optional (because they all have default values), and now we have to make something happen within the class body for each of them. Since there is yet a bit of work to be done, we will take it up in earnest on the next page. However, we have a crystal clear idea of where we want to take this, and it won't be so very difficult. And at the end of the next page, we will be able to test the finished MenuButton class and make it crank out some customized buttons!

