Hi Everyone,
We are getting down to the end of the term. Only 3 weeks remaining.
For this week's posting, we will be doing two exercises, both of which synthesize many of the things that we've been working with over the last several weeks. The first one is to create buttons completely out of code and place them onto the stage of a document. The second is to start working on the music player, so we'll be going back and using some of the code learned a few weeks ago from the classes that pertained to our "music player" that played on the names of the songs. Now we have to add music and a few more things.
Carter-
- WEEK 11
- Classwork (11/24)
- LINK last week's class files
- Homework:
- Exercise 1: This applied example is a class that creates functioning buttons entirely with code, and it's based on our work with the graphics class this week, and with the display from last week. We will create a new custom class that creates a rectangle. This method is similar to the methods that create the circle, ellipse and rounded-rectangle of this week's class exercise.
- This class declaration will have 4 functions within it.
- Constructor—The first function is the main function. We have seen this type function before for as many times as we have created classes. The primary function of the class is always the one that actually generates or constructs, puts all things together to form the class object.
- Button Creator—The next function creates our button object with all of its most obvious properties, including the 4 button states; however, this button is an empty object and will not yet contain any graphics.
- Rectangle Creator—This function creates the rectangle graphic that will be inserted into the button above. We will use the graphics class to do this as we did this week in class to create the face.
- Label Text Creator—The last function creates the text-field that will go inside the button so that there is something to read that tells us the name of the button and gives us an idea of what will happen when you click on it.
- We must begin by creating a folder for the actionscript file we will be working with this week. If you have not done so, please create a wk11 directory within your projects directory.
- Next, open up a new .as file and save it into the correct folder as CreateRectBtn.as.
- We'll start our coding by declaring a few variables which we will use to define the appearance of our rectangular button. We will do this when we instantiate our CreateRectBtn class. The resulting button will have the 4 states we normally associate with buttons: UP, OVER, DOWN, and HIT. When complete with this class, all that will remain is a listener to be attached to the button that will activate some function of your choosing.
- package wk11
- {
- import flash.display.*; /* allows access to all properties of the display class built-in to Flash. Remember, the asterisk allows us to be non-specific as to which aspects of the display class we will to import, but rather import ALL of them */
- import flash.text.*; /* allows access to all properties of the text class built-in to Flash. */
- import fl.motion.Color; /* allows access to all properties of the Color class built-in to Flash. */
- import flash.events.*; /* allows access to all events held within the events class built-in to Flash. */
- public class CreateRectBtn extends MovieClip { /* this tells us that the custom class that we are now creating will build upon, or extend the capabilities of the MovieClip class that is built-in to Flash. Recall that the MovieClip class is very similar to the Sprite class, only it contains timeline information, and therefore is able to have any animation within it that you wish to add */
- private var _w:Number;
- private var _h:Number;
- private var _lineWt:Number;
- private var _col:uint;
- private var _txtCol:uint;
- private var _txt:String;
- }
- }
- Save the file above again into the correct directory. The name you give the file should be the SAME NAME as the NAME OF THE CLASS.
- You will notice that we have six private variables above. As we did in the past, the first character in all of our private variables is the underscore (_) character. This gives us a visual cue as to whether it is public or private later on. Also, recall, that the values of private variables may NOT be altered in the instance of the class that is created in the .fla file.
- The first variable is going to be for the width, the second is for the height, the third is for the height, the fourth is for the button color, the fifth is for the text color, and the sixth is for the actual text that will serve as a label for the button. Notice that it is typed as STRING.
- The next step, as you may recall, is to add the constructor function. After the name of the constructor function as we did for our music player a few weeks ago, we listed the variables that are necessary for beginning our button. In this case, we need all six. When them come inside the parentheses as they do below, we call them parameters. That means that our six class variables above, are equivalent to the parameters of the constructor function below. Note, however, that the parameter names do NOT have the underlines in front of the names:
- package wk11
- {
- import flash.display.*;
- import flash.text.*;
- import fl.motion.Color;
- import flash.events.*;
- import flash.display.MovieClip;
- public class CreateRectBtn extends MovieClip {
- private var _w:Number;
- private var _h:Number;
- private var _lineWt:Number;
- private var _col:uint;
- private var _txtCol:uint;
- private var _txt:String;
- public function CreateRectBtn()
- {
- }
- }
- }
- The next step is to connect the parameters to the variables:
- package wk11
- {
- import flash.display.*;
- import flash.text.*;
- import fl.motion.Color;
- import flash.events.*;
- import flash.display.MovieClip;
- public class CreateRectBtn extends MovieClip {
- private var _w:Number;
- private var _h:Number;
- private var _lineWt:Number;
- private var _col:uint;
- private var _txtCol:uint;
- private var _txt:String;
- public function CreateRectBtn()
- {
- _w = 80;
- _h = 20;
- _lineWt = 2;
- _col = 0x006666;
- _txt = "hello";
- _txtCol = 0x002222;
- }
- }
- }
- Since this is our constructor function, we should construct our object; and as this class is intended for the creation of a button, we will call on the simpleButton object that is built-in to Flash. Therefore, let us start that 2nd function. This 2nd function, goes directly below the closing curly bracket of the first constructor function.
- As mentioned above, this function is to generate and create a button with all of its 4 parts, the up, over, down, and hit states. Notice here on the first line of the function code down below that the return value is SimpleButton.
- This function, therefore, has a primary job of creating the button states. Button states, which appear depending on what the user is doing with them (just looking at them, mousing over them, clicking on them, etc), involve determining the colors of the button as the user interacts with it. We will use what's known as the Color class to do this. This is a class similar to any other that we have used, such as the display or the graphics classes that are built-in to Flash.
- The method (aka function) that we will be using to set the color is known as interpolateColor(). What this method does is find a color that is mixture of two other colors. Given two colors, the method calculates a color that is in between the two provided. A third item in the function (its 3rd parameter) tells how much of one or the other colors that the new interpolated color should contain.
- For example, if your two colors were black and white, and then the 3rd parameter was 0.5, the new interpolated color would be EXACTLY IN THE MIDDLE between the black and white. It would be a middle gray. If your 3rd parameter, however, were 0.1, then the new interpolated color would be closer to the 2nd color and be a very light gray as a result. If it were 0.9, it would be closer to the first color and thus a very dark gray.
- private function createBtn():SimpleButton
- {
- var ovCol:uint = Color.interpolateColor();
- var dnCol:uint = Color.interpolateColor();
- }
- The variable ovCol is the variable that will hold the color for the OVER state of the button; and the variable dnCol is the variable that will hold the color for the DOWN state of the button.
- Okay, great, so we have the interpolateColor() methods above, but we don't have the colors themselves yet. That is because we have to type into the method the colors so that it can determine the mixed color:
- private function createBtn():SimpleButton
- {
- var ovCol:uint = Color.interpolateColor(_col, 0xFFFFFF);
- var dnCol:uint = Color.interpolateColor(_col, 0x000000);
- }
- Above, we have the two colors. In both, notice, we used the _col variable. This is the original variable up at the top that we declared as part of the class to contain the color of the button. So, there is going to be an as yet undetermined main color for the button.
- Notice above also that for the ovCol, the over color, that we are trying to find a color in between the original color (_col), and a new color, 0xFFFFFF, which is white. That means that for the over color we will have a lighter version of the original color.
- Similarly, for dnCol, the down color, we are trying to find a color in between the original color (_col), and another new color, 0x000000, which is black. This means that for the down color we will have a darker version of the original color.
- Next, we have to add the 3rd parameter that I mentioned above to tell whether we want the new interpolated color to be closer to the original color, or closer to the new color added. If I wanted 50% of the original and 50% of the new color, exactly in the middle, I'd use the value of 0.5; however, I want it to be closer to the 2nd color (either white or black), so I'll use a value of 30% for the 3rd parameter, which would be 0.3.
- private function createBtn():SimpleButton
- {
- var ovCol:uint = Color.interpolateColor(_col, 0xFFFFFF, 0.3);
- var dnCol:uint = Color.interpolateColor(_col, 0x000000, 0.3);
- }
- The next thing we need to add is the line of code that actually creates the button object. This will entail using a rectangle graphic that we will have to create with code (we are going to use the graphics class that we worked with when drawing the face). This means that, the moment after we create the new button object with ActionScript, we will have to call upon another function to do the job of creating the actual graphics using code we learned to draw the face:
- private function createBtn():SimpleButton
- {
- var ovCol:uint = Color.interpolateColor(_col, 0xFFFFFF, 0.3);
- var dnCol:uint = Color.interpolateColor(_col, 0x000000, 0.3);
- /* The line below creates the button object as an instance of SimpleButton */
- var btn:SimpleButton = new SimpleButton()
- The lines below, create the different states of the button. After the equal sign (=) it calls on our next function that does the work of actually creating the rectangle shape
- btn.upState = createRect();
- btn.overState = createRect();
- btn.downState = createRect();
- The line below makes the HIT state the SAME as the OVER state of the button:
- btn.hitTestState = btn.upState;
- return btn;
- }
- Even though we're not quite finished with this function, let's move on to the third one.
Now that we have the colors for the different states of the button, what we have left to do here is actually to create the graphics to fit into the different states. To do that we'll just draw a rectangle in our next function, the createRect() function. We will call this function each time we need a new rectangle shape, which means it will be called for each state of the button, 3 times. - Notice here on the first line of the function that the return value has a TYPE of SHAPE. Try to recall that whenever we create variables or pass values from one function to another that we must TYPE the data. That is what we are doing there. The type of data we are creating is a shape.
- We then proceed, as we did in class last week, to use the graphics class to draw the rectangle and color it with code. This function should be typed directly below the curly bracket of the 2nd function.
- The first line creates the shape object:
- var rect:Shape = new Shape();
- The next line indicates what style of line we are using. If you recall from class this week, this can take 3 parameters. These parameters indicate the line-weight (thickness), the color of the line, and the alpha value of the line. If there is no alpha value stated, the default value is 100%, or 1.0.
- rect.graphics.lineStyle(_lineWt, _col);
- The variable above, _lineWt, will have a numerical value to determine the thickness of the outline; and the variable, _col is the original color.
- The next line of code determines the fill color as we learned in class this week. It has two parameters, the color value and then the alpha value. So, what we have is the original color set to an alpha of 50% (0.5):
- rect.graphics.beginFill(col, 0.5);
- We then must actually draw the rectangle. We didn't use this method in class, but used similar ones, the rounded-rectangle, the ellipse, and the circle. The logic is the same. It takes 4 parameters: The first two numbers are the x/y coordinates, and the 2nd 2 numbers are the width and the height.
- rect.graphics.drawRect(0, 0, _w, _h);
- The next line ends the fill as we saw this week in class. It is a method that must be started and then stopped when desired:
- rect.graphics.endFill();
- The last line returns a value. This is the same thing that we saw back when we were doing the music player, but then we just returned numbers or text, numerical and string values. In this case, we are returning an object, an entire rectangle shape.
- return rect;
- Therefore, what we end up with is a shape with both an outline and a fill, and that is sent back to the previous function that we were working on:
- private function createRect(col:uint):Shape
- {
- var rect:Shape = new Shape();
- rect.graphics.lineStyle(_lineWt, _col);
- rect.graphics.beginFill(col, 0.5);
- rect.graphics.drawRect(0, 0, _w, _h);
- rect.graphics.endFill();
- return rect;
- }
- Now that we have the shape of the button drawn, let's return to the previous function. Its job is to create the button object with all of its 4 states. It also sets the colors of those states using the interpolateColor() method. What we haven't done is put those two things together: when creating the different states of the buttons, we haven't told the function which color should be used for which button state:
- private function createBtn():SimpleButton
- {
- var ovCol:uint = Color.interpolateColor(_col, 0xFFFFFF, 0.3);
- var dnCol:uint = Color.interpolateColor(_col, 0x000000, 0.3);
- var btn:SimpleButton = new SimpleButton()
- btn.upState = createRect(_col);
- btn.overState = createRect(ovCol);
- btn.downState = createRect(dnCol);
- btn.hitTestState = btn.upState;
- return btn;
- }
- So we have our first three functions almost completely done, but not quite: our constructor function, remember, is missing a few things. Recall, what we have done in that function so far is only declare our variables. This means we have only stated their names and what type of variables they will be, such as numerical or string variables. We haven't constructed anything yet, and that's just what a constructor function should do. In truth, it should just trigger the beginning of the construction of the buttons in this case; and there are two things that it needs to trigger:
- The construction of the rectangular button; and
- The construction of a text box that goes inside that button.
- To handle the first of the two above tasks, we will simply call on our createBtn() function:
- var btn:SimpleButton = createBtn();
- The following is what this one line of code does:
- It creates a variable (var btn) which we've given the name of btn.
- Next, we have typed that variable as a SimpleButton, not as a String nor as a Number nor an integer, but as a simple button object (var btn:SimpleButton);
- The last piece in that line is to call the function that actually builds the button. So far we have the function written; and just now, we have created the code object, the SimpleButton object. What we don't have, however, is the trigger that puts those two things together, that calls our function, createBtn().
- What happens next is immediately after declaring that variable, we activate our createBtn() function so as to provide our variable with a value. That function then goes to work to create the rectangular button.
- When it is done, it returns a value; but in this case, as mentioned, it returns NOT a simple value but an entire object, a button object.
- This completed button object then gets put inside the btn variable.
- This means that btn is the name of our simple button.
- After that, we have to add it as a child object onto the stage:
- var btn:SimpleButton = createBtn();
- addChild(btn);
- With our button complete, we now have to create a text field. A text field is a built-in object in ActionScript just as a SimpleButton is a built-in object, so we just type our variable as a TextField.
- var txt:TextField
- In order to create this text field, however, we have to call upon another function, a function we have NOT yet created. We'll do it in exactly the same way we called upon the createBtn() function. Therefore, let's call it createTxt():
- var txt:TextField = createTxt();
- Like the button object above, we also have to add that text field object to the stage as a child:
- var txt:TextField = createTxt();
- addChild(txt);
- Now, we will add one last line to this function. We do NOT want this text field to be accessible to the mouse. What this means is that we don't want it clickable or selectable. This makes sense because the user will not be editing the text, neither adding to it nor subtracting from it. We don't want the user to interact with it at all, other than simply reading it as the name of the button. This is important because if this step is not taken, the cursor wil change to the I-beam text editing cursor when you mouse over the button. Moreover, the button will NOT be clickable where covered by the text field if we do not disable it. If we do not take this last step, the user will not be able to click on the button properly:
- var txt:TextField = createTxt();
- addChild(txt);
- txt.mouseEnabled = false;
- The completed constructor function now looks like this:
- public function CreateRectBtn()
- {
- _w = 80;
- _h = 20;
- _lineWt = 2;
- _col = 0x006666;
- _txt = "hello";
- _txtCol = 0x00222222;
- var btn:SimpleButton = createBtn();
- addChild(btn);
- var tField:TextField = createTxt();
- addChild(tField);
- tField.mouseEnabled = false;
- }
- Finally, we must create the 4th and final function. As mentioned above in number 29 above, this is the createTxt() function that we call when we must create our text field for the button. Basically, it just goes about formatting a text field the same way we would do in the Properties panel. We start out by creating a TextField object. We follow that by creating a TextFormat object. Notice in the first line of code below that the return value is the whole text field.
- private function createTxt():TextField
- {
- var tField:TextField = new TextField();
- var format:TextFormat = new TextFormat();
- }
- Now, we give the text field a width and a height:
- private function createTxt():TextField
- {
- var tField:TextField = new TextField();
- tField.width = _w;
- tField.height = _h;
- var format:TextFormat = new TextFormat();
- }
- Next, we must format the text field with a font, a color, a font-size, a font-weight, and an alignment:
- private function createTxt():TextField
- {
- var tField:TextField = new TextField();
- tField.width = _w;
- tField.height = _h;
- var format:TextFormat = new TextFormat();
- format.font = "Verdana";
- format.color = _txtCol;
- format.size = 10;
- format.bold = true;
- format.align = TextFormatAlign.CENTER;
- }
- Now, we must apply our formatting instructions that are inside our format variable to our text field:
- private function createTxt():TextField
- {
- var tField:TextField = new TextField();
- tField.width = _w;
- tField.height = _h;
- var format:TextFormat = new TextFormat();
- format.font = "Verdana";
- format.color = _txtCol;
- format.size = 10;
- format.bold = true;
- format.align = TextFormatAlign.CENTER;
- tField.defaultTextFormat = format;
- }
- After that, we must put some actual text into the text field. To do that, we use the _txt variable that we declared at the beginning of this exercise. We will also prevent the user from selecting the text:
- private function createTxt():TextField
- {
- var tField:TextField = new TextField();
- tField.width = _w;
- tField.height = _h;
- var format:TextFormat = new TextFormat();
- format.font = "Verdana";
- format.color = _txtCol;
- format.size = 10;
- format.bold = true;
- format.align = TextFormatAlign.CENTER;
- tField.defaultTextFormat = format;
- tField.text = _txt;
- tField.selectable = false;
- return tField;
- }
- Excellent, we have completed the class for our use, which will be, first, to create a single button on the stage of an .fla file, and then, second, to create a series of buttons. So, make sure you save this file one last time, and then open up a new .fla file named button_test.fla. Make sure you save this into the project directory, NOT the same directory as the .as file which should be in the wk11 directory. Doing this means that all we have to do is to type the document class in the space provided in the properties panel.
- You do NOT have to do anything else in this document at all. Just save it after you type the document class and test it.
- Great! Now that the button is there on the stage AND it also works, let's put 4 more onto the stage. To do that, all we need is a for-loop that loops around 5 times. This should go inside the class within the constructor function. But where?
- We put it around those lines of code whose job it is to create the button, create the text, and then place them onto the stage:
- public function CreateRectBtn()
- {
- _w = 80;
- _h = 20;
- _lineWt = 2;
- _col = 0x006666;
- _txt = "hello";
- _txtCol = 0x002222;
- for (var i:int = 0; i < 5; i++)
- {
- var btn:SimpleButton = createBtn();
- addChild(btn);
- var tField:TextField = createTxt();
- addChild(tField);
- tField.mouseEnabled = false;
- }
- }
- That'll do it, but if you were to test it now, chances are you'd only see one button there. Don't worry, the ARE all there, they're just stacked on top of each other. They're just all in the same position. That means we have to change the X and/or Y position of the buttons as they are created. The first one can be where it is now, but the 2nd one has to be over a little, and the 3rd one has to be over a bit more than that (and so on) so they won't be overlapping. How do we do that?
- We must take into consideration the WIDTH of the button when determining the horizontal position, also known as the X position of the object on the stage.
- If we add 1 width to the X position of the 2nd button, it won't be on top the first. If we add 2 widths to the X position of the 3rd button, it won't be on top the first nor the second. If we add 3 widths to the X position of the 4th button, it won't be on top the first 3. If we add 4 widths to the X position of the 5th button, it won't be on top the other four (and so on if we had more of them)!!!
- Notice above I typed 1 width, 2 widths, 3 widths, 4 widths, and 5 widths. The key there are the numbers 1 - 5. There is only one other thing that increments up like that, and that is the counter variable that we have created in the for-loop, i. We'll use that to position the buttons.
- public function CreateRectBtn()
- {
- _w = 80;
- _h = 20;
- _lineWt = 2;
- _col = 0x0066666;
- _txt = "hello";
- _txtCol = 0x002222;
- for (var i:int = 0; i < 5; i++)
- {
- var btn:SimpleButton = createBtn();
- addChild(btn);
- btn.x = i * (btn.width);
- var tField:TextField = createTxt();
- addChild(tField);
- tField.mouseEnabled = false;
- }
- }
- But as it is here, you should notice, all the buttons are enjambed: there is no space between each button. Let's add a bit of space:
- public function CreateRectBtn()
- {
- _w = 80;
- _h = 20;
- _lineWt = 2;
- _col = 0x006666;
- _txt = "hello";
- _txtCol = 0x002222;
- for (var i:int = 0; i < 5; i++)
- {
- var btn:SimpleButton = createBtn();
- addChild(btn);
- btn.x = i * (btn.width + 5);
- var tField:TextField = createTxt();
- addChild(tField);
- tField.mouseEnabled = false;
- }
- }
- Now, let's put different text within each button. To do this, we'll use an array. First we'll declare the array at the top where we declare all the other properties. Then, in the constructor function, we'll populate the array with 5 text elements. Finally, we'll position the tField in the same way we position the btn:
- package wk11
- {
- import flash.display.*;
- import flash.text.*;
- import fl.motion.Color;
- import flash.events.*;
- import flash.display.MovieClip;
- public class CreateRectBtn extends MovieClip {
- private var _w:Number;
- private var _h:Number;
- private var _lineWt:Number;
- private var _col:uint;
- private var _txtCol:uint;
- private var _txt:String;
- private var _txtArray:Array;
- public function CreateRectBtn()
- {
- _w = 80;
- _h = 20;
- _lineWt = 2;
- _col = 0x006666;
- _txt = "hello";
- _txtCol = 0x002222;
- _txtArray = new Array("hello", "hola", "ça va", "ciao", "bye");
- for (var i:int = 0; i < 5; i++)
- {
- var btn:SimpleButton = createBtn();
- addChild(btn);
- btn.x = i * (btn.width + 5);
- var tField:TextField = createTxt();
- addChild(tField);
- tField.mouseEnabled = false;
- _txt = _txtArray[i];
- tField.x = i * (btn.width + 5);
- }
- }
- }
- }
- Exercise 2: Now you on your own must create a new method (function) within the class that causes something, anything, to happen when the user clicks on the button, even just a trace action is fine so long as it happens when the user clicks on the buttons. If you can manage to get something different to happen for each button, then even better.