Friday, January 14, 2011

Encapsulation - The Big Picture

Summary: Learn two different approaches for using ActionScript to create complex custom components having the same programming interface, the same user interface, and the same behavior.









Preface

General

NOTE: 

Note that all references to ActionScript in this lesson are references to version 3 or later.
This tutorial lesson is part of a series of lessons dedicated to object-oriented programming (OOP) with ActionScript .
The three main characteristics of an object-oriented program
Object-oriented programs exhibit three main characteristics:
  • Encapsulation
  • Inheritance
  • Polymorphism
In this and the next two lessons, I will explain and illustrate these three characteristics from a big-picture viewpoint. Following that, I will get down in the weeds and start explaining in detail how to use ActionScript for object-oriented programming (OOP) .
Several ways to create and launch ActionScript programs
There are several ways to create and launch programs written in the ActionScript programming language. Many of the lessons in this series will use Adobe Flex as the launch pad for the sample ActionScript programs.
An earlier lesson titled The Default Application Container provided information on how to get started programming with Adobe's Flex Builder 3. (See Baldwin's Flex programming website .) You should study that lesson before embarking on the lessons in this series.
Some understanding of Flex MXML will be required
I also recommend that you study all of the lessons on Baldwin's Flex programming website in parallel with your study of these ActionScript lessons. Eventually you will need to understand both ActionScript and Flex and the relationships that exist between them in order to become a successful ActionScript programmer.
Will emphasize ActionScript code
It is often possible to use either ActionScript code or Flex MXML code to achieve the same result. Insofar as this series of lessons is concerned, the emphasis will be on ActionScript code even in those cases where Flex MXML code may be a suitable alternative.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.

Figures

  • Figure 1 . Screen output for Encapsulation01.
  • Figure 2 . File structure for the project named Encapsulation01.

Listings

Supplemental material

I recommend that you also study the other lessons in my extensive collection of online programming tutorials. You will find a consolidated index at www.DickBaldwin.com .

General background information

In addition to the three explicit characteristics of encapsulation inheritance , and polymorphism , an object-oriented program also has an implicit characteristic of abstraction .
What is abstraction?
Abstraction is the process by which we specify a new data type, often referred to an abstract data type or ADT.
How does abstraction relate to encapsulation?
Encapsulation is the process of gathering an ADT's data representation and behavior into one encapsulated entity. In other words, encapsulation converts from the abstract to the concrete.
Some analogies
You might think of this as being similar to converting an idea for an invention into a set of blueprints from which it can be built, or converting a set of written specifications for a widget into a set of drawings that can be used by the machine shop to build the widget.
Automotive engineers encapsulated the specifications for the steering mechanism of my car into a set of manufacturing drawings. Then manufacturing personnel used those drawings to produce an object where they exposed the interface (steering wheel) and hid the implementation (levers, bolts, etc.) .
In all likelihood, the steering mechanism object contains a number of other more-specialized embedded objects, each of which has state and behavior and also has an interface and an implementation .
The interfaces for those embedded objects aren't exposed to me, but they are exposed to the other parts of the steering mechanism that use them.

Abstraction

Abstraction is the specification of an abstract data type, which includes a specification of the type's data representation and its behavior . In particular,
  • What kind of data can be stored in an entity of the new type, and
  • What are all the ways that the data can be manipulated?
A new type
For our purposes, an abstract data type is a new type (not intrinsic to the ActionScript language) . It is not one of the primitive data types that are built into the programming language(such as Boolean, int, Number, String, and uint) .
Already known to the compiler
The distinction in the previous paragraph is very important. The data representation and behavior of the intrinsic or primitive types is already known to the compiler and cannot normally be modified by the programmer.
Not known to the compiler
The representation and behavior of an abstract type is not known to the compiler until it is defined by the programmer and presented to the compiler in an appropriate manner.
Define data representation and behavior in a class
ActionScript programmers define the data representation and the behavior of a new type (present the specification to the compiler) using the keyword class . In other words, the keyword class is used to convert the specification of a new type into something that the compiler can work with; a set of plans as it were. To define a class is to go from the abstract to the concrete.
Create instances of the new type
Once the new type (class) is defined, one or more objects of that type can be brought into being (instantiated, caused to occupy memory) .
Objects have state and behavior
Once instantiated, the object is said to have state and behavior . The state of an object is determined by the current values of the data that it contains and the behavior of an object is determined by its methods.
The state and behavior of a GUI Button object
For example, if we think of a GUI Button as an object, it is fairly easy to visualize the object's state and behavior.
A GUI Button can usually manifest any of a number of different states: size, position, depressed image, not depressed image, label, etc. Each of these states is determined by data stored in the instance variables of the Button object at any given point in time. (The combination of one or more instance variables that determine a particular state is often referred to as a property of the object.)
Similarly, it is not too difficult to visualize the behavior of a GUI Button . When you click it with the mouse, some specific action usually occurs.
An ActionScript class named Button
If you dig deeply enough into the ActionScript class library, you will find that there is a class named Button . Each individual Button object in a Flex application is an instance of the ActionScript class named Button .
The state of Button objects
Each Button object has instance variables, which it does not share with other Button objects. The values of the instance variables define the state of the button at any given time. Other Button objects in the same scope can have different values in their instance variables. Hence they can have a different state.
The behavior of a Button object
Each Button object also has certain fundamental behaviors such as responding to a mouse click event or responding to a mouseOver event.
The ActionScript programmer has control over the code that is executed in response to the event. However, the ActionScript programmer has no control over the fact that a Buttonobject will respond to such an event. The fact that a Button will respond to certain event types is an inherent part of the type specification for the Button class and can only be modified by modifying the source code for the Button class.

Encapsulation

If abstraction is the design or specification of a new type, then encapsulation is its definition and implementation.
A programmer defines the data representation and the behavior of an abstract data type into a class, thereby defining its implementation and its interface. That data representation and behavior is then encapsulated in objects that are instantiated from the class.
Expose the interface and hide the implementation
According to good object-oriented programming practice, an encapsulated design usually exposes the interface and hides the implementation. This is accomplished in different ways with different languages.
Just as most of us don't usually need to care about how the steering mechanism of a car is implemented, a user of a class should not need to care about the details of implementation for that class.
The user of the class (the using programmer) should only need to care that it works as advertised. Of course this assumes that the user of the class has access to good documentation describing the interface and the behavior of objects instantiated from the class.
Should be able to change the implementation later
For a properly designed class, the class designer should be able to come back later and change the implementation, perhaps changing the type of data structure used to store data in the object, and the using programs should not be affected by the change.
Class member access control
Object-oriented programming languages usually provide the ability to control access to the members of a class. For example, ActionScript, C++ and Java all use the keywords public ,private , and protected to control access to the individual members of a class. In addition, ActionScript and Java add a fourth level of access control, which is called internal in ActionScript and is called package-private in Java. (See Class property attributes in a companion document on ActionScript Resources.)
Public, private, and protected
To a first approximation, you can probably guess what public and private mean. Public members are accessible by all code that has access to an object of the class. Private members are accessible only by members belonging to the class.
The protected keyword is used to provide inherited classes with special access to the members of their base classes.
A public user interface
In general, the user interface for a class consists of the public methods. (The variables in a class can also be declared public but this is generally considered to be bad programming practice unless they are actually constants. )
For a properly designed class, the class user stores, reads, and modifies values in the object's data by calling the public methods on a specific instance (object) of the class. (This is sometimes referred to as sending a message to the object asking it to change its state) .
ActionScript has a special form of method, often called an implicit setter method or an implicit getter method that is specifically used for this purpose. (You will see several implicit setter methods in the program that I will explain later in this lesson.)
Normally, if the class is properly designed and the implementation is hidden, the user cannot modify the values contained in the instance variables of the object without going through the prescribed public methods in the interface.
Not a good design by default
An object-oriented design is not a good design by default. In an attempt to produce good designs, experienced object-oriented programmers generally agree on certain design standards for classes. For example, the data members (instance variables) are usually private unless they are constants. The user interface usually consists only of public methods and includes few if any data members.
Of course, there are exceptions to every rule. One exception to this general rule is that data members that are intended to be used as symbolic constants are made public and defined in such a way that their values cannot be modified.
The methods in the interface should control access to, or provide a pathway to the private instance variables.
Not bound to the implementation
The interface should be generic in that it is not bound to any particular implementation. Hence, the class author should be able to change the implementation without affecting the using programs so long as the interface doesn't change.
In practice, this means that the signatures of the interface methods should not change, and that the interface methods and their arguments should continue to have the same meaning.

Preview

In this lesson, I will present and briefly explain a program with an output that consists of a Flex user interface containing two custom component objects as shown in Figure 1. Each of the objects is intended to represent a single multiple-choice question in an online test. (See Creating Online Tests using Custom ActionScript Components here for a detailed explanation of the code.)
Figure 1: Screen output for Encapsulation01.
Screen output for Encapsulation01.
Missing image.
The two question objects in Figure 1 have the same behavior. And as you will see later, the classes from which they were instantiated have the same user interfaces. However, the classes are implemented in significantly different ways.

Discussion and sample code

Will discuss in fragments
I will discuss the code in this lesson in fragments. Listing 1 shows the mxml code that instantiates the two component objects shown in Figure 1. A complete listing of the file namedEncapsulation01.mxml is provided in Listing 12 near the end of the lesson.

LISTING 1: Mxml code to instantiate two custom component objects.

<!--The following code instantiates an object of the class
named QuizA for a multiple-choice quiz question with three
choices.-->

<cc:QuizA
question=
"Which of the following is not the name of one of the 
seven dwarfs?"
choice0="Dopey"
choice1="Sneezy"
choice2="Harold"
answer="2" 
/>

<!--The following code instantiates an object of the class
named QuizB for a multiple-choice quiz question with three
choices. Note that the interface is exactly the same as
for the class named QuizA. However, the implementation of
QuizB is radically different from QuizA.-->

<cc:QuizB
question=
"Which of the following is not the name of one of the 
seven dwarfs?"
choice0="Dopey"
choice1="Sneezy"
choice2="Harold"
answer="2" 
/>
The important thing...
The important thing to note in Listing 1 is that, with the exception of the name of the class being instantiated in each case (QuizA and QuizB) , the mxml code is identical for the two cases.
The code that begins with cc:Quiza produces the top question object in Figure 1 and the code that begins with cc:Quizb produces the bottom question object in Figure 1.
Since the mxml code for the two objects is identical, the user interface for the two classes must also be identical.
The project file structure
The Flex project file structure that I used for this program is fairly typical. However, before getting into a discussion of the two class files, I will show you how the files are organized in the Flex project as shown in Figure 2.
Figure 2: File structure for the project named Encapsulation01.
File structure for the project named Encapsulation01.
Missing image.
Classes named QuizA and QuizB
As you can see from Listing 1 and Figure 2, two class files named QuizA.as and QuizB.as were used to instantiate the two objects shown in Figure 1. Complete listings for those two files are provided in Listing 13 and Listing 14 near the end of the lesson.
Remember, this is a big-picture discussion
Because this is a "big-picture" lesson, I won't explain either of these classes in detail in this lesson. (You can find technical details for a class very similar to QuizA in Creating Online Tests using Custom ActionScript Components here you are interested in technical details at this point.) Instead, I will compare the two class definitions from a big-picture viewpoint.
For brevity, I will also delete some of the code such as import directives.
Beginning of the class named QuizA
The class named QuizA begins in Listing 2.

LISTING 2: Beginning of the class named QuizA.

package CustomClasses{
    //Import directives deleted for brevity.
  
  public class QuizA extends VBox{
    private var theQuestion:TextArea;
    private var choice00:RadioButton;
    private var choice01:RadioButton;
    private var choice02:RadioButton;
    private var checkButton:Button;
    private var result:TextArea;
    
    private var theAnswer:String;//numeric string
    private var correctAnswer:String;//actual string
    private var vboxWidth:int = 375;
Variable declarations
The important thing to note in Listing 2 is the declaration of six instance variables of three different component types (beginning with the first line that reads private var . These variables will be used to hold references to the six different components shown in each question object in Figure 1.
TextArea, RadioButton, and Button objects
The white rectangular areas at the top and the bottom of each question object in Figure 1 is an object of the class named TextArea . You can probably spot the three RadioButton objects and the Button object in each question object.
Beginning of the class named QuizB
The class named QuizB begins in Listing 3.

LISTING 3: Beginning of the class named QuizB.

package CustomClasses{
    //Import directives deleted for brevity.
  
  public class QuizB extends VBox{
    private var components:Array = 
        new Array(new TextArea(),//theQuestion
                  new RadioButton(),
                  new RadioButton(),
                  new RadioButton(),
                  new Button(),//checkButton
                  new TextArea());//result
    
    private var theAnswer:String;//numeric string
    private var correctAnswer:String;//actual string
    private var vboxWidth:int = 375;
An array with six elements
The six instance variables that I referred to in Listing 2 were replaced by a single array having six elements in Listing 3. The creation of the array begins with the first line in Listing 3 that readsprivate var .
This is the major change that was made in the implementation of QuizB relative to the implementation of QuizA . This change will have significant ramifications throughout the remainder of the code whenever it is necessary to access a reference that points to one of the six components.
Populated with six component objects
It is also worth noting that the array elements are populated with references to component objects for QuizB when the array is created in Listing 3. The new component objects aren't instantiated until later in QuizA .
Implicit setter methods for QuizA
Listing 4 shows five implicit setter methods for the class named QuizA .

LISTING 4: Implicit setter methods for QuizA.

    public function set question(textIn:String):void{
        theQuestion.text = textIn;
    }//end implicit setter
    
    public function set answer(answerIn:String):void{
        theAnswer = answerIn;
    }//end implicit setter
    
    public function set choice0(choice:String):void{
        choice00.label=choice;
    }//end implicit setter
    
    public function set choice1(choice:String):void{
        choice01.label=choice;
    }//end implicit setter
    
    public function set choice2(choice:String):void{
        choice02.label=choice;
    }//end implicit setter
Setter methods are called by mxml code
Briefly, these methods are called by the code in Listing 1 when values are assigned to the following five mxml attributes:
  • question
  • choice0
  • choice1
  • choice2
  • answer
See Defining Custom MXML Components here if you are interested in learning more about implicit setter methods at this point in time.
Implicit setter methods for QuizB
Listing 5 shows five implicit setter methods for QuizB that serve the same purpose as the five implicit setter methods for QuizA . Note the differences in the code that results from using individual variables to reference the components in QuizA and using an array to reference the components in QuizB .

LISTING 5: Implicit setter methods for QuizB.

    public function set question(textIn:String):void{
        components[0].text = textIn;
    }//end implicit setter
    
    public function set answer(answerIn:String):void{
        theAnswer = answerIn;
    }//end implicit setter
    
    public function set choice0(choice:String):void{
        components[1].label=choice;
    }//end implicit setter
    
    public function set choice1(choice:String):void{
        components[2].label=choice;
    }//end implicit setter
    
    public function set choice2(choice:String):void{
        components[3].label=choice;
    }//end implicit setter
Expose the interface but hide the implementation
These five setter methods, along with the class constructors, constitute the entire user interface for each class. If you examine Listing 13 and Listing 14, you will see that these five setter methods and the constructor are the only public members of either class. All other members of the classes are declared private .
Furthermore:
  • The names of the five methods are the same in both classes.
  • The names and types of the required parameters for the five methods are the same in both classes.
  • The five methods serve the same purpose in both classes.
  • The ultimate behavior of objects instantiated from the two classes is the same.
Therefore, the exposed user interface is the same for both classes but the hidden implementation is significantly different between the two classes.
Purpose of the setter methods
The purpose of the setter methods in both cases is to store mxml attribute values in the text property of the TextArea at the top of each question object in Figure 1 and to store mxml attribute values in the label property of each of the RadioButton objects in each question object in Figure 1. In addition, one of the setter methods stores an attribute value in the variable named theAnswer .
If you compare the code in Figure 4 and Figure 5, you will see that Figure 4 stores the incoming parameter values by way of the contents of four instance variables whereas Figure 5 stores the incoming parameter values by way of the contents of four elements in the array.
Constructor for QuizA
Listing 6 shows the constructor for the class named QuizA .

LISTING 6: Constructor for QuizA.

    public function QuizA(){//constructor
      width=vboxWidth;
      setStyle("borderStyle","solid");
      setStyle("backgroundColor",0xffff00);
      
      theQuestion = new TextArea();
      theQuestion.editable = false;
      theQuestion.width=vboxWidth - 2;
      addChild(theQuestion);

      choice00 = new RadioButton();
      choice00.groupName="radioButtonGroup";
      addChild(choice00);
      
      choice01 = new RadioButton();
      choice01.groupName="radioButtonGroup";
      addChild(choice01);
      
      choice02 = new RadioButton();
      choice02.groupName="radioButtonGroup";
      addChild(choice02);
      
      checkButton = new Button();
      checkButton.label = "Click to Check Answer";
      checkButton.addEventListener(MouseEvent.CLICK,
                                   checkButtonHandler);
      addChild(checkButton);
      
      result = new TextArea();
      result.editable = false;
      result.width=vboxWidth - 2;
      result.visible=false;
      addChild(result);
      
      //Register an event listener that will be
      // executed when this object has been fully
      // constructed. It will set the height of
      // the VBox based on the sum of the heights
      // of the components.
      this.addEventListener(
                    mx.events.FlexEvent.CREATION_COMPLETE,
                    vboxCompleteHandler);
    }//end constructor
There are numerous differences between the code in the constructors for QuizA and QuizB . Every statement that needs to access a reference pointing to one of the six component objects in Figure 1 is different between the two constructors because of the difference in the way those references are stored. There are other differences as well, which are shown in Listing 6.
Constructor for QuizB
The constructor for the class named QuizB is shown in Listing 7.

LISTING 7: Constructor for QuizB.

    public function QuizB(){//constructor
      width=vboxWidth;
      setStyle("borderStyle","solid");
      setStyle("backgroundColor",0xffff00);

      components[0].editable = false;//theQuestion
      components[0].width=vboxWidth - 2;
      
      components[1].groupName="radioButtonGroup";
      components[2].groupName="radioButtonGroup";
      components[3].groupName="radioButtonGroup";
      
      //checkButton
      components[4].label = "Click to Check Answer";
      components[4].addEventListener(MouseEvent.CLICK,
                                   checkButtonHandler);
      
      //result
      components[5].editable = false;
      components[5].width=vboxWidth - 2;
      components[5].visible=false;

      //Add GUI components to the VBox.
      for(var cnt:int = 0;cnt < components.length;cnt++){
        addChild(components[cnt]);
      }//end for loop

      //Register an event listener that will be
      // executed when this VBox object has been fully
      // constructed. It will set the height of
      // the VBox based on the sum of the heights
      // of the components.
      this.addEventListener(
                    mx.events.FlexEvent.CREATION_COMPLETE,
                    vboxCompleteHandler);
    }//end constructor
In addition to the differences in the way that references to the six component objects are accessed, Listing 7 contains other significant differences as well.
No code to instantiate the six component objects
First, there is no code in Listing 7 to instantiate the six component objects. As I mentioned earlier, those objects were instantiated and used to populate the six-element array referred to bycomponents when the array was created.
Only one statement calling the addChild method in QuizB
Next, you will notice that there are six statement making calls to the addChild method of the VBox container in Listing 6. Calls to that method cause the components to be added as children of the container.
Those six calls to the addChild method were consolidated into a single call inside a for loop in Listing 7. This is possible because the six references are contained in an array whose elements can be accessed using a numeric index.
The checkButtonHandler for QuizB
Listing 8 shows the checkButtonHandler method for the class named QuizA .

LISTING 8: The checkButtonHandler for QuizA.

    private function checkButtonHandler(
                                   event:MouseEvent):void{
      result.visible=true;
      
      if(theAnswer == "0"){
        correctAnswer = choice00.label;
      }else if(theAnswer == "1"){
        correctAnswer = choice01.label;
      }else{
        correctAnswer = choice02.label;
      }//end else
                
      if((theAnswer=="0" && choice00.selected) || 
           (theAnswer=="1" && choice01.selected) ||
           (theAnswer=="2" && choice02.selected)){
        
        result.setStyle("color",0x00ff00);
        result.text = "Correct\nCorrect Answer is: "
                     + correctAnswer;
      }else{
        result.setStyle("color",0xff0000);
        result.text = "Wrong\nCorrect Answer is: "
                     + correctAnswer;
      }//end else
    }//end checkButtonHandler
This is the event handler method that is registered for a click event on the Button by the code in Listing 6.
The checkButtonHandler for QuizB
Listing 9 shows the corresponding checkButtonHandler method for the class named QuizB .

LISTING 9: The checkButtonHandler for QuizB.

    private function checkButtonHandler(
                                   event:MouseEvent):void{
      components[5].visible=true;
      
      if(theAnswer == "0"){
        correctAnswer = components[1].label;
      }else if(theAnswer == "1"){
        correctAnswer = components[2].label;
      }else{
        correctAnswer = components[3].label;
      }//end else
                
      if((theAnswer=="0" && components[1].selected) || 
         (theAnswer=="1" && components[2].selected) ||
         (theAnswer=="2" && components[3].selected)){
        
        components[5].setStyle("color",0x00ff00);
        components[5].text = 
                           "Correct\nCorrect Answer is: "
                           + correctAnswer;
      }else{
        components[5].setStyle("color",0xff0000);
        components[5].text = "Wrong\nCorrect Answer is: "
                     + correctAnswer;
      }//end else
    }//end checkButtonHandler
This is the event handler method that is registered for a click event on the Button by the code in Listing 7.
Differences between the code
The differences between the methods named checkButtonHandler in the two classes result from the different access requirements for the three radio buttons and the text area at the bottom of the question objects in Figure 1.
In one case (QuizA) , access is by way of the named reference variables that were declared in Listing 2. In the other case (QuizB) , access to each component object's reference is by way of an element of the array that was created in Listing 3.
The vboxCompleteHandler for QuizA
The vboxCompleteHandler method for the class named QuizA is shown in Listing 10.

LISTING 10: The vboxCompleteHandler for QuizA.

    private function vboxCompleteHandler(
                          event:mx.events.FlexEvent):void{

      this.height = 
        theQuestion.height
        + choice00.height
        + choice01.height
        + choice02.height
        + checkButton.height
        + result.height
        + 36;//six spaces per compnent
    }//end vboxCompleteHandler
    //==================================================//
  }//end class
}//end package
Registered by the code in Listing 6
This is the event handler method that was registered on the VBox container by the code near the bottom of Listing 6. The purpose of this event handler is to execute when the VBoxconstruction is complete and to set the height of the VBox container to the heights of the six individual components plus six pixels per component to account for the space between components.
Listing 10 accesses the individual height values by way of the six reference variables declared in Listing 2.
The vboxCompleteHandler for QuizB
The vboxCompleteHandler method for QuizB is shown in Listing 11.

LISTING 11: The vboxCompleteHandler for QuizB.

    private function vboxCompleteHandler(
                          event:mx.events.FlexEvent):void{

      this.height = 0;
      
      for(var cnt:int = 0;cnt < components.length;cnt++){
        this.height += components[cnt].height + 6;
      }//end for loop

    }//end vboxCompleteHandler
    //==================================================//
  }//end class
}//end package
Same purpose as before
This event handler method has the same purpose as the event handler method with the same name in Listing 10.
Once again, because the references to the components are stored in an array, a for loop can be used to access and get the height of each of the components and to compute the overall height as the sum of those heights plus six pixels for each component.
The end of the program
Listing 10 and Listing 11 each signal the end of the class and the end of the program.

Run the program

I encourage you to run this program from the web. Then copy the code from Listing 12, Listing 13, and Listing 14. Use that code to create a Flex project. Compile and run the project. Experiment with the code, making changes, and observing the results of your changes. Make certain that you can explain why your changes behave as they do.

Resources

I will publish a list containing links to ActionScript resources as a separate document. Search for ActionScript Resources in the Connexions search box.

Complete program listings

Complete listings of the Flex MXML and ActionScript source code discussed in this lesson are provided in Listing 12 through Listing 14.

LISTING 12: Source code for Encapsulation01.mxml.

<?xml version="1.0" encoding="utf-8"?>

<!--TestGenerator01
  This application illustrates the concept of exposing
  the interface and hiding the implementation. Two
  classes are defined from which custom components are
  instantiated. Components instantiated from both classes
  have the same user interface but they have radically 
  different implementations.-->
  
<mx:Application 
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:cc="CustomClasses.*">
  <mx:Label text="ENCAPSULATION DEMO"/>
  <mx:Label text=" Copyright 2009 R.G.Baldwin" />


<!--The following code instantiates an object of the class
named QuizA for a multiple-choice quiz question with three
choices.-->
<cc:QuizA
question=
"Which of the following is not the name of one of the 
seven dwarfs?"
choice0="Dopey"
choice1="Sneezy"
choice2="Harold"
answer="2" 
/>

<!--The following code instantiates an object of the class
named QuizB for a multiple-choice quiz question with three
choices. Note that the interface is exactly the same as
for the class named QuizA. However, the implementation of
QuizB is radically different from QuizA.-->
<cc:QuizB
question=
"Which of the following is not the name of one of the 
seven dwarfs?"
choice0="Dopey"
choice1="Sneezy"
choice2="Harold"
answer="2" 
/>

  <!--The purpose of the follow code is to control the
      appearance of the GUI components.-->
  <mx:Style>
  RadioButton {
  fontWeight: bold;
  fontSize: 14;
  }
  Label{
  fontWeight: bold;
  fontSize: 18;
  color:  #FFFF00;
  }
  Button{
  fontWeight: bold;
  fontSize: 14;
  }
  TextArea{
  fontWeight: bold;
  fontSize: 14;
  }
  </mx:Style>
</mx:Application>

LISTING 13: Source code for QuizA.as.

package CustomClasses{
    import flash.events.*;
    import mx.containers.VBox;
    import mx.controls.Button;
    import mx.controls.RadioButton;
    import mx.controls.TextArea;
    import mx.events.FlexEvent;
  
  public class QuizA extends VBox{
    private var theQuestion:TextArea;
    private var choice00:RadioButton;
    private var choice01:RadioButton;
    private var choice02:RadioButton;
    private var checkButton:Button;
    private var result:TextArea;
    
    private var theAnswer:String;//numeric string
    private var correctAnswer:String;//actual string
    private var vboxWidth:int = 375;
    //==================================================//
    
    public function set question(textIn:String):void{
        theQuestion.text = textIn;
    }//end implicit setter
    
    public function set answer(answerIn:String):void{
        theAnswer = answerIn;
    }//end implicit setter
    
    public function set choice0(choice:String):void{
        choice00.label=choice;
    }//end implicit setter
    
    public function set choice1(choice:String):void{
        choice01.label=choice;
    }//end implicit setter
    
    public function set choice2(choice:String):void{
        choice02.label=choice;
    }//end implicit setter
    //==================================================//
    
    public function QuizA(){//constructor
      width=vboxWidth;
      setStyle("borderStyle","solid");
      setStyle("backgroundColor",0xffff00);
      
      theQuestion = new TextArea();
      theQuestion.editable = false;
      theQuestion.width=vboxWidth - 2;
      addChild(theQuestion);

      choice00 = new RadioButton();
      choice00.groupName="radioButtonGroup";
      addChild(choice00);
      
      choice01 = new RadioButton();
      choice01.groupName="radioButtonGroup";
      addChild(choice01);
      
      choice02 = new RadioButton();
      choice02.groupName="radioButtonGroup";
      addChild(choice02);
      
      checkButton = new Button();
      checkButton.label = "Click to Check Answer";
      checkButton.addEventListener(MouseEvent.CLICK,
                                   checkButtonHandler);
      addChild(checkButton);
      
      result = new TextArea();
      result.editable = false;
      result.width=vboxWidth - 2;
      result.visible=false;
      addChild(result);
      
      //Register an event listener that will be
      // executed when this object has been fully
      // constructed. It will set the height of
      // the VBox based on the sum of the heights
      // of the components.
      this.addEventListener(
                    mx.events.FlexEvent.CREATION_COMPLETE,
                    vboxCompleteHandler);
    }//end constructor
    //==================================================//
    
    private function checkButtonHandler(
                                   event:MouseEvent):void{
      result.visible=true;
      
      if(theAnswer == "0"){
        correctAnswer = choice00.label;
      }else if(theAnswer == "1"){
        correctAnswer = choice01.label;
      }else{
        correctAnswer = choice02.label;
      }//end else
                
      if((theAnswer=="0" && choice00.selected) || 
           (theAnswer=="1" && choice01.selected) ||
           (theAnswer=="2" && choice02.selected)){
        
        result.setStyle("color",0x00ff00);
        result.text = "Correct\nCorrect Answer is: "
                     + correctAnswer;
      }else{
        result.setStyle("color",0xff0000);
        result.text = "Wrong\nCorrect Answer is: "
                     + correctAnswer;
      }//end else
    }//end checkButtonHandler
    //==================================================//
    
    private function vboxCompleteHandler(
                          event:mx.events.FlexEvent):void{
      //Set the height equal to the sum of the
      // heights of the components plus six 
      // pixels per component to account for the
      // space between components.
      this.height = 
        theQuestion.height
        + choice00.height
        + choice01.height
        + choice02.height
        + checkButton.height
        + result.height
        + 36;//six spaces per compnent
    }//end vboxCompleteHandler
    //==================================================//
  }//end class
}//end package

LISTING 14: Source code for QuizB.as.

//This is an update of the class named QuizA. This version
// stores references to all of the GUI components in a
// six-element array and uses for loops to process them
// where appropriate. Note that the GUI components are
// instantiated and their references are stored in the
// array when the array is created.

package CustomClasses{
    import flash.events.*;
    import mx.containers.VBox;
    import mx.controls.Button;
    import mx.controls.RadioButton;
    import mx.controls.TextArea;
    import mx.events.FlexEvent;
  
  public class QuizB extends VBox{

    //References to six GUI components are stored in the
    // following array.
    private var components:Array = 
        new Array(new TextArea(),//theQuestion
                  new RadioButton(),
                  new RadioButton(),
                  new RadioButton(),
                  new Button(),//checkButton
                  new TextArea());//result
    
    private var theAnswer:String;//numeric string
    private var correctAnswer:String;//actual string
    private var vboxWidth:int = 375;
    //==================================================//
    
    public function set question(textIn:String):void{
        components[0].text = textIn;
    }//end implicit setter
    
    public function set answer(answerIn:String):void{
        theAnswer = answerIn;
    }//end implicit setter
    
    public function set choice0(choice:String):void{
        components[1].label=choice;
    }//end implicit setter
    
    public function set choice1(choice:String):void{
        components[2].label=choice;
    }//end implicit setter
    
    public function set choice2(choice:String):void{
        components[3].label=choice;
    }//end implicit setter
    //==================================================//
    
    public function QuizB(){//constructor
      width=vboxWidth;
      setStyle("borderStyle","solid");
      setStyle("backgroundColor",0xffff00);

      components[0].editable = false;//theQuestion
      components[0].width=vboxWidth - 2;
      
      components[1].groupName="radioButtonGroup";
      components[2].groupName="radioButtonGroup";
      components[3].groupName="radioButtonGroup";
      
      //checkButton
      components[4].label = "Click to Check Answer";
      components[4].addEventListener(MouseEvent.CLICK,
                                   checkButtonHandler);
      
      //result
      components[5].editable = false;
      components[5].width=vboxWidth - 2;
      components[5].visible=false;

      //Add GUI components to the VBox.
      for(var cnt:int = 0;cnt < components.length;cnt++){
        addChild(components[cnt]);
      }//end for loop

      //Register an event listener that will be
      // executed when this VBox object has been fully
      // constructed. It will set the height of
      // the VBox based on the sum of the heights
      // of the components.
      this.addEventListener(
                    mx.events.FlexEvent.CREATION_COMPLETE,
                    vboxCompleteHandler);
    }//end constructor
    //==================================================//
    
    private function checkButtonHandler(
                                   event:MouseEvent):void{
      components[5].visible=true;
      
      if(theAnswer == "0"){
        correctAnswer = components[1].label;
      }else if(theAnswer == "1"){
        correctAnswer = components[2].label;
      }else{
        correctAnswer = components[3].label;
      }//end else
                
      if((theAnswer=="0" && components[1].selected) || 
         (theAnswer=="1" && components[2].selected) ||
         (theAnswer=="2" && components[3].selected)){
        
        components[5].setStyle("color",0x00ff00);
        components[5].text = 
                           "Correct\nCorrect Answer is: "
                           + correctAnswer;
      }else{
        components[5].setStyle("color",0xff0000);
        components[5].text = "Wrong\nCorrect Answer is: "
                     + correctAnswer;
      }//end else
    }//end checkButtonHandler
    //==================================================//
    
    private function vboxCompleteHandler(
                          event:mx.events.FlexEvent):void{
      //Set the height equal to the sum of the
      // heights of the components plus six 
      // pixels per component to account for the
      // space between components.
      this.height = 0;
      for(var cnt:int = 0;cnt < components.length;cnt++){
        this.height += components[cnt].height + 6;
      }//end for loop

    }//end vboxCompleteHandler
    //==================================================//
  }//end class
}//end package

Miscellaneous

This section contains a variety of miscellaneous materials.

NOTE: 

Housekeeping material
  • Module name: Encapsulation - The Big Picture
  • Files:
    • ActionScript0106\ActionScript0106.htm
    • ActionScript0106\Connexions\ActionScriptXhtml0106.htm

1 comment:

Related Posts Plugin for WordPress, Blogger...

java

Popular java Topics