Skip navigation
Currently Being Moderated

Newbie: Comparing Arrays

Sep 12, 2012 4:47 PM

Hi,

I want to create a screen (using just AS3 code) with a number of user input questions on it.

e.g. Question stem: What is the capital of France?   Answer: Paris.

I have the code for displaying the "question stem" and the "text entry box".

But I do not know what code to use to compare the two arrays:

Array 1: correct answer, Array 2: user input answer.

User will click a Submit button once they have answered all the questions. i.e. One Submit button.

I would also like the text "Correct" or "Incorrect" to appear to the right of the text entry box.

I'm new to AS3 so any changes to the code i've provided would be welcome.

 

Below is the code for 3 questions. (without the Submit button code)

 

package

{

import flash.display.Sprite;

import flash.text.TextField;

import flash.text.TextFormat;

 

public class Main_questions extends Sprite

{

 

// DEFAULT TEXT FORMAT

var textFormat:TextFormat = new TextFormat("verdana", 9)

 

public function Main_questions():void

 

// QUESTIONS IN A LOOP       

var Q_stem_array:Array = new Array();

           

for(var i:int = 0; i < 3; i++) 

{

var Question:TextField = new TextField();

Question.defaultTextFormat = textFormat;

Question.border = false;

Question.width = 300;

Question.height = 20;

Question.x = 30;

Question.y = i * 35 + 70;

Q_stem_array.push(Question);

               

addChild(Question);

}

Q_stem_array[0].text = "1. What is the Capital of Ireland?"; 

Q_stem_array[1].text = "2. What is the Capital of France?";  

Q_stem_array[2].text = "3. What is the Capital of Spain?";

 

// TEXT ENTRY BOXES (TEBs) IN A LOOP

for(var i:int = 0; i < 3; i++)

{

var TEBfield:TextField = new TextField();

TEBfield.defaultTextFormat = textFormat;

TEBfield.border = true;

TEBfield.width = 200;

TEBfield.height = 20;

TEBfield.x = 200;

TEBfield.y = i * 35 + 70;

TEBfield.type = "input"; 

textArray.push(TEBfield);

                          

addChild(TEBfield);

}

 

}

}

 
Replies
  • kglad
    72,220 posts
    Jul 21, 2002
    Currently Being Moderated
    Sep 12, 2012 10:11 PM   in reply to donalall

    do you know how to create and populate the two (correct answers and user input) arrays?

     

    if yes, loop through one of them and compare their elements:

     

    function scoreF():int{

    var score:int = 0;

    for(var i:int=0;i<correctAnswerA.length;i++){

    if(correctAnswerA[i].toLowerCase()==userInputA[i].toLowerCase()){

    score++;

    }

    }

    return score;

    }

     
    |
    Mark as:
  • kglad
    72,220 posts
    Jul 21, 2002
    Currently Being Moderated
    Sep 13, 2012 6:39 AM   in reply to donalall

    whereever you detect that the user has completed their answer to the current question, use:

     

    userInputA.push(yourinputtextfield.text);

     

    and you call scoreF() when the quiz is completed and you want to display the user's score.

     
    |
    Mark as:
  • kglad
    72,220 posts
    Jul 21, 2002
    Currently Being Moderated
    Sep 13, 2012 1:26 PM   in reply to donalall

    yes, you need:

     

    var userInputA:Array=[];

     

    to declare and define an array.

     

    when the submit button is clicked (eg, in your click listener), you can use:

     

    for(var i:int=1;i<=n;i++){

    userInputA.push(this["tf_"+i].text);  // where your input textfield for question 1 is tf_1, for question 2 is tf_2 etc

    }

     
    |
    Mark as:
  • kglad
    72,220 posts
    Jul 21, 2002
    Currently Being Moderated
    Sep 13, 2012 4:23 PM   in reply to donalall

    you need to create those textfields.  if you're using code to create them, use:

     

     

     

    for(var i:int = 0; i < 3; i++)          // Text Field Boxes (tf_) in a Loop

    {

    this["tf_"+i]= new TextField();

    this["tf_"+i].defaultTextFormat = textFormat;

    this["tf_"+i].border = true;

    this["tf_"+i].width = 200;

    this["tf_"+i].height = 20;

    this["tf_"+i].x = 200;

    this["tf_"+i].y = i * 35 + 70;

    this["tf_"+i].type = "input"; 

    addChild(this["tf_"+i]);

    }

     

    or save yourself some typing and use:

     

    for(var i:int = 0; i < 3; i++)          // Text Field Boxes (tf_) in a Loop

    {

    this["tf_"+i]= new TextField();

    with(this["tf_"+i]){

    defaultTextFormat = textFormat;

    border = true;

    width = 200;

    height = 20;

    x = 200;

    y = i * 35 + 70;

    type = "input";

    addChild(this["tf_"+i]);

    }

     
    |
    Mark as:
  • kglad
    72,220 posts
    Jul 21, 2002
    Currently Being Moderated
    Sep 14, 2012 4:54 AM   in reply to donalall

    copy and paste the code you used.

     
    |
    Mark as:
  • kglad
    72,220 posts
    Jul 21, 2002
    Currently Being Moderated
    Sep 14, 2012 5:21 AM   in reply to donalall

    make your sprite sublclass dynamic or extend the movieclip class.

     

    p.s. please mark helpful/correct responses.

     
    |
    Mark as:
  • kglad
    72,220 posts
    Jul 21, 2002
    Currently Being Moderated
    Sep 14, 2012 5:58 AM   in reply to donalall

    you'll have to make that dynamic, too:

     


    public dynamic class Main_Sept13 extends MovieClip

     

    or, if you want to use sprite:

     


    public class Main_Sept13 extends Sprite
     
    |
    Mark as:
  • kglad
    72,220 posts
    Jul 21, 2002
    Currently Being Moderated
    Sep 14, 2012 7:24 AM   in reply to donalall

    if you only created 3 textfields you shouldn't be checking 4.  use:

     

    function buttonClickHandler(event:MouseEvent):void

    {

    for(var i:int=0;i<3;i++){

    UserInput.push(this["tf_"+i].text);

     

    p.s.  you should start marking the helpful/correct responses so others can quickly find them.

     
    |
    Mark as:
  • kglad
    72,220 posts
    Jul 21, 2002
    Currently Being Moderated
    Sep 14, 2012 8:30 AM   in reply to donalall

    is that code in your Main_questions class?  is UserInput defined AND initialized.  if yes, yes and yes, what does the following show:

     

     

     

    {

    for(var i:int=0;i<3;i++){

    trace(UserInput.length,this)

    trace(i,this["tf"_"+i])

    UserInput.push(this["tf_"+i].text);

     
    |
    Mark as:
  • kglad
    72,220 posts
    Jul 21, 2002
    Currently Being Moderated
    Sep 14, 2012 8:59 AM   in reply to donalall

    i don't know what you're calling your Main class.

     

    but all the code you've been showing should be in the same class or you have a scope problem.

     

     

    if all your code is in the same class, what do those trace() functions reveal?

     
    |
    Mark as:
  • kglad
    72,220 posts
    Jul 21, 2002
    Currently Being Moderated
    Sep 14, 2012 5:27 PM   in reply to donalall

    you have more than one problem with that setup.  copy and paste your updated Main_questions class code.

     
    |
    Mark as:
  • Currently Being Moderated
    Sep 15, 2012 6:00 AM   in reply to donalall

    Conceptually, this kind of applications should have entities that supplies data (data provider) and links visuals to the data.

     

    In your case data is questions/answers while visuals are TextField instances.

     

    I would strongly advise against using dynamic classes (that allows for adding properties dynamically at runtime via associative array notation), especially in this kind of cases. While utilizing dynamic features sometimes is useful, in the majority of cases it present major headaches down the road and is very inefficient from performance standpoint.

     

    Below is a fully functional class that accomplishes what you are looking for. Role of data provider is accomplished by the questions array. This is an array of objects that accomplish the linkages between questions, answers and TextFields at both configuration and user interaction phases. Read comments.

     

    All features are dynamic except I use name “checkButton” for the submit button.

     

    Theoretically this application asks for at least two more classes but, because you stated that you are new to AS3 – this is a sufficient beginning.

     

    At last, you should get into a habit to declare as few variables as possible and NEVER declare variables in the loops. Declaring variables inside loop bodies is a pretty bad practice.

     

     

    package
    {
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
        import flash.text.TextFieldType;
        import flash.text.TextFormat;
        
        public class Main_questions extends Sprite
        {
            // use single object that acts as a data provider and links questions, answers and runtime object
            private var questions:Array;
            // DEFAULT TEXT FORMAT
            private var textFormat:TextFormat = new TextFormat("Verdana", 9);
            // correct feedback format
            private var correctTF:TextFormat = new TextFormat("Verdana", 9, 0x008000);
            // incorrect feedback format
            private var incorrectTF:TextFormat = new TextFormat("Verdana", 9, 0xDF0000);
            
            public function Main_questions():void
            {
                init();
            }
            
            private function init():void 
            {
                initData();
                drawQuestions();
            }
            /**
             * This method inititate data and populates it with questions/answers
             */
            private function initData():void 
            {
                questions = [];
                // questions
                var question:Array = ["What is the Capital of Ireland?", "What is the Capital of France?", "What is the Capital of Spain?"];
                // answers
                var answer:Array = ["Dublin", "Paris", "Madrid"];
                for (var i:int = 0; i < question.length; i++) {
                    // push new object into questions array - this uses literal object instantiation notation {}
                    questions.push( { question: question[i], answer: answer[i] } );
                }
            }
            /**
             * This method draws text fields and adds them to their correcponding objects
             */
            private function drawQuestions():void 
            {
                // use/recycle the same variable - it is more efficient
                var textField:TextField;
                // var to control x positions
                var nextX:Number = 30;
                // var to control y position
                var nextY:Number = 0;
                // loop through questions and create textfileds
                // for each loop is faster than for loop
                // on each loop iteration object element is used from appropriate position on the array
                for each(var q:Object in questions) {
                    // CREATE QUESTION TextField
                    textField = new TextField();
                    textField.defaultTextFormat = textFormat;
                    textField.width = 300;
                    textField.height = 20;
                    textField.x = nextX;
                    textField.y = nextY;
                    // get question text from the object in questions array
                    // ordinal inserted based on the index of question in the array
                    textField.text = (questions.indexOf(q) + 1) + ". " + q.question;
                    // change nextX
                    nextX += textField.width;
                    // add field to display list
                    addChild(textField);
                    // add text field to the object for future linkage to answer
                    // this step is optional because actual answer string will be used
                    q.questionText = textField;
                    // CREATE ANSWER input field
                    // note - the same variable textField is used again - NOT the same instance but different instance of THE SAME variable
                    textField = new TextField();
                    textField.defaultTextFormat = textFormat;
                    textField.border = true;
                    textField.width = 200;
                    textField.height = 20;
                    textField.type = TextFieldType.INPUT;
                    textField.x = 30;
                    textField.x = nextX;
                    textField.y = nextY;
                    // change nextX to accomodate feedback TextField
                    nextX += textField.width;
                    // add field to display list
                    addChild(textField);
                    // add text field to the object for future linkage to answer
                    q.answerText = textField;
                    // CREATE FEEDBACK field
                    // again - use the same textField variable to create new instances
                    textField = new TextField();
                    textField.defaultTextFormat = correctTF;
                    textField.width = 100;
                    textField.height = 20;
                    textField.x = nextX + 10;
                    textField.y = nextY;
                    // add field to display list
                    addChild(textField);
                    // add feedback field to the object for linkage to question
                    q.feedback = textField;
                    // reset positions defaults for the next loop iteration
                    nextX = 30;
                    nextY += textField.height + 10;
                    
                }
                // assuming that button name is checkButton
                checkButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
            }
            
            private function buttonClickHandler(e:MouseEvent):void 
            {
                // loop through the objects in questions array and compare answers
                for each(var q:Object in questions) {
                    // remove spaces from answers in case user types the in the beginning and the end
                    q.answerText.text = String(q.answerText.text).replace(/^\s+|\s+$/, "");
                    // compare answers in lower cases
                    if (q.answer.toLowerCase() == q.answerText.text.toLowerCase()) {
                        TextField(q.feedback).text = "correct";
                        TextField(q.feedback).setTextFormat(correctTF);
                    }
                    else {
                        TextField(q.feedback).text = "incorrect!";
                        TextField(q.feedback).setTextFormat(incorrectTF);
                    }
                }
            }
        }
    }
    
     
    |
    Mark as:
  • Currently Being Moderated
    Sep 16, 2012 10:58 AM   in reply to donalall

    While waiting for Godot,  I decided to show a more OOP approach to your application. It may be a bit difficult to digest at first, but if you have time and desire – look into what is happening and how things work together in the classes below.

     

    To test – just put all the classes into the same directory as you FLA and make MainQuestions the document class.

     

    I split functionality into 5 different classes. One of the OOP principals are to make objects very specialized. This approach presents with much better scalability.

     

    Some of the highlights:

    1. Document class became very small and it does only two things – places visuals on display list and monitors how user interacts with the button. Technically even these two aspects shouldbe delegated to another class but from illustration standpoint it is not very relvant.
    2. Data is separated into a special class QuestionsData. It may not be apparent at first but this way you can get data different ways and not change a bit of other code that uses this data. For example, in the future you may want to decide to load data at runtime as XML. Still – your application will function the same way despite the fact that data acquisition, parsing and storage change.
    3. I introduced shuffling capabilities in the QuestionsData class to randomize questions – it feels more natural for quizzes.
    4. QuestionLine class is a display object that contains all visuals that pertain to a single question. Note how data is used. Also this class takes care of user entry validation.
    5. Note that because of QuestionLine class, QuestionsContainer class doesn’t have to deal with specifics of question related visuals in depth. QuestionsContainer just creates QuestionLine instances and redistributes data. See init() method of QuestionsContainer.
    6. QuestionTextFiled class. It feels a touch as an overkill but this class allows for unification of some shared functionality between TextFields that are used in QuestionLine. As a result – there is less coding on QuestionLine level.

     

    There are some other tricks of the trade in the code but they are secondary.

     

    Class MainQuestions - document class

     

     

    package
    {
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        
        public class MainQuestions extends Sprite
        {
            
            // container that displays questions
            private var container:QuestionsContainer;
            
            public function MainQuestions():void
            {
                init();
            }
            
            private function init():void
            {
                // instnatiate container
                container = new QuestionsContainer(new QuestionsData());
                addChild(container);
                container.x = container.y = 30;
                // reposition button to the bottom right
                checkButton.x = container.x + container.width - checkButton.width;
                checkButton.y = container.y + container.height + 10;
                
                checkButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
            }
            
            private function buttonClickHandler(e:MouseEvent):void
            {
                container.checkAnswers();
            }
        
        }
    }
    

     

    Class QuestionsData

     

     

    package
    {
        
        public class QuestionsData extends Object
        {
            public var questions:Array;
            
            public function QuestionsData()
            {
                init();
            }
            
            private function init():void
            {
                // array of questions
                var q:Array = ["What is the Capital of Ireland?", "What is the Capital of France?", "What is the Capital of Spain?", "What is the Capital of Malaysia?", "What is the Capital of New York?", "What is the Capital of California?"];
                // array of answers
                var a:Array = ["Dublin", "Paris", "Madrid", "Kuala Lumpur", "Albany", "Sacramento"];
                questions = [];
                // populate array with objects that link questions and answers
                for (var i:int = 0; i < q.length; i++)
                {
                    questions.push({question: q[i], answer: a[i]});
                }
                // randomize
                shuffle();
            }
            
            /**
             * Randomizes questions
             */
            public function shuffle():void
            {
                var value:Object;
                var random:int = 0;
                var i:int = questions.length;
                while (i--)
                {
                    random = Math.random() * (i + 1);
                    value = questions[random];
                    questions[random] = questions[i];
                    questions[i] = value;
                }
            }
        
        }
    }
    

     

     

    Class QuestionLine

     

     

    package
    {
        import flash.display.Sprite;
        import flash.text.TextFieldAutoSize;
        import flash.text.TextFieldType;
        import flash.text.TextFormat;
        
        public class QuestionLine extends Sprite
        {
            // text fields
            private var question:QuestionTextFiled, answer:QuestionTextFiled, feedback:QuestionTextFiled;
            // text formats
            private var correctFormat:TextFormat = new TextFormat("Verdana", 9, 0x008000);
            private var incorrectFormat:TextFormat = new TextFormat("Verdana", 9, 0xDF0000);
            // x gap between fields
            private var gap:Number = 10;
            // related to question data
            private var data:Object;
            // question ordinal
            private var index:int = 0;
            // row background colors
            private var rowColors:Array = [0xE8E8E8, 0xFFFFFF];
            // internal padding
            private var padding:Number = 4;
            
            public function QuestionLine(data:Object, index:int)
            {
                this.data = data;
                this.index = index;
                init();
            }
            
            private function init():void
            {
                question = new QuestionTextFiled();
                answer = new QuestionTextFiled();
                feedback = new QuestionTextFiled();
                
                question.x = padding;
                question.y = answer.y = feedback.y = padding;
                
                answer.width = 150
                feedback.width = 60;
                
                question.autoSize = TextFieldAutoSize.LEFT;
                
                question.text = String(index + 1) + ". " + data.question;
                
                answer.type = TextFieldType.INPUT;
                
                addChild(question);
                addChild(answer);
                addChild(feedback);
            }
            
            /**
             * Provides width of the question field - used for even alignment of
             * textfields in other instances.
             */
            public function get questionWidth():Number
            {
                return question.width;
            }
            
            /**
             * Used to even up fields
             */
            public function set questionWidth(value:Number):void
            {
                // reset autosize so that we can set precise width
                question.autoSize = TextFieldAutoSize.NONE;
                question.width = value;
                // reposition other fields to accomodate passed value
                answer.x = question.x + question.width + gap;
                feedback.x = answer.x + answer.width + gap;
                // draw background based on whether index is odd or even
                graphics.beginFill(rowColors[index % 2]);
                graphics.drawRect(0, 0, width + padding * 2, height + padding * 2);
                // draw buttom line - mainly for the cases when background is white 
                // so there is always line that separates the instance visually
                graphics.lineStyle(1, rowColors[1 - index % 2]);
                graphics.moveTo(0, height);
                graphics.lineTo(width, height);
            }
            
            /**
             * Validates user entry and compare entry with the correct answer
             */
            public function checkAnswer():void
            {
                // validate entries
                // remove leading and double spaces
                answer.text = answer.text.replace(/^\s+|\s+$/, "").replace(/\s{2,}/g, " ");
                if (answer.text.toLowerCase() == data.answer.toLowerCase())
                {
                    feedback.text = "correct";
                    feedback.setTextFormat(correctFormat);
                    // make it proper
                    answer.text = data.answer;
                }
                else
                {
                    feedback.text = "incorrect!";
                    feedback.setTextFormat(incorrectFormat);
                }
            }
        
        }
     
    }
    

     

    Class QuestionsContainer

     

     

    package
    {
        import flash.display.Sprite;
        
        public class QuestionsContainer extends Sprite
        {
            private var data:QuestionsData;
            // array of question lines
            private var qLines:Array;
            // maximum width of question field among all question lines used
            private var maxQWidth:Number = 0;
            
            public function QuestionsContainer(data:QuestionsData)
            {
                this.data = data;
                init();
            }
            
            private function init():void
            {
                // instance of question line that is reused
                var qLine:QuestionLine;
                qLines = [];
                
                for (var i:int = 0; i < data.questions.length; i++)
                {
                    qLine = new QuestionLine(data.questions[i], i);
                    // add line to array for further processing
                    qLines.push(qLine);
                    // grab width if it is the largest one
                    maxQWidth = Math.max(maxQWidth, qLine.questionWidth);
                }
                // now that we know the widest line - we can place objects on display list
                placeQuestion();
            }
            
            /**
             * Places question lines on display list and sets largest width for even alignment
             */
            private function placeQuestion():void
            {
                // vertical distance between questions
                var gap = 6;
                // used to set y
                var nextY:Number = 0;
                for each (var q:QuestionLine in qLines)
                {
                    addChild(q);
                    q.questionWidth = maxQWidth;
                    q.y = nextY;
                    nextY += q.height;
                }
            }
            
            public function checkAnswers():void
            {
                // loop through the lines and invoke answer checking on them
                for each (var q:QuestionLine in qLines)
                    q.checkAnswer();
            }
        
        }
     
    }
    

     

     

    Class QuestionTextFiled

     

     

    package
    {
        import flash.text.TextField;
        import flash.text.TextFormat;
        
        public class QuestionTextFiled extends TextField
        {
            private var defaultFormat:TextFormat = new TextFormat("Verdana", 9);
            
            public function QuestionTextFiled()
            {
                init();
            }
            
            private function init():void
            {
                defaultTextFormat = defaultFormat;
                height = Number(defaultFormat.size) * 2;
                multiline = wordWrap = false;
            }
            
            /**
             * Overrides default behavior and adds border/background
             */
            override public function set type(value:String):void
            {
                super.type = value;
                border = true;
                borderColor = 0xC0C0C0;
                background = true;
            }
        
        }
     
    }
    
     
    |
    Mark as:
  • Currently Being Moderated
    Sep 17, 2012 5:23 PM   in reply to donalall

    As far as the original class goes - below is one of the ways to implement what you asked about.

     

    I don't have time to do the same in the multiple classes implementation though. I trust you can do it yourself.

     

    One piece of advice.

     

    Conventionally, Classes are named starting with Upper case. It is prudent to name all variables and methods starting with lower case - this improves code readability. In your instance variable "Score" should be "score."

     

    Read comments.

     

     

    package
    {
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        import flash.text.TextField;
        import flash.text.TextFieldType;
        import flash.text.TextFormat;
        
        public class Main_questions extends Sprite
        {
            // use single object that acts as a data provider and links questions, answers and runtime object
            private var questions:Array;
            // DEFAULT TEXT FORMAT
            private var textFormat:TextFormat = new TextFormat("Verdana", 9);
            // correct feedback format
            private var correctTF:TextFormat = new TextFormat("Verdana", 9, 0x008000);
            // incorrect feedback format
            private var incorrectTF:TextFormat = new TextFormat("Verdana", 9, 0xDF0000);
            
            private var checkButton:Sprite;
            // text field that displays score feedback
            private var scoreFeedback:TextField;
            // answers score value
            private var score:int = 0;
            
            public function Main_questions():void
            {
                init();
            }
            
            private function init():void
            {
                drawcheckButton();
                initData();
                drawQuestions();
            }
            
            /**
             * This method inititate data and populates it with questions/answers
             */
            private function initData():void
            {
                questions = [];
                // questions
                var question:Array = ["What is the Capital of Ireland?", "What is the Capital of France?", "What is the Capital of Spain?", "What is the Capital of Malaysia?", "What is the Capital of New York?", "What is the Capital of California?"];
                // answers
                var answer:Array = ["Dublin", "Paris", "Madrid", "Kuala Lumpur", "Albany", "Sacramento"];
                for (var i:int = 0; i < question.length; i++)
                {
                    // push new object into questions array - this uses literal object instantiation notation {}
                    questions.push({question: question[i], answer: answer[i]});
                }
            }
            
            /**
             * This method draws text fields and adds them to their correcponding objects
             */
            private function drawQuestions():void
            {
                // use/recycle the same variable - it is more efficient
                var textField:TextField;
                
                scoreFeedback = new TextField();
                scoreFeedback.defaultTextFormat = textFormat;
                scoreFeedback.autoSize = "left";
                scoreFeedback.width = 400;
                scoreFeedback.height = 20;
                addChild(scoreFeedback);
                
                scoreFeedback.x = scoreFeedback.y = 30;
                // var to control x positions
                var nextX:Number = scoreFeedback.x;
                // var to control y position
                var nextY:Number = scoreFeedback.y + scoreFeedback.height + 20;
                // loop through questions and create textfileds
                // for each loop is faster than for loop
                // on each loop iteration object element is used from appropriate position on the array
                for each (var q:Object in questions)
                {
                    // CREATE QUESTION TextField
                    textField = new TextField();
                    textField.defaultTextFormat = textFormat;
                    textField.width = 300;
                    textField.height = 20;
                    textField.x = nextX;
                    textField.y = nextY;
                    // get question text from the object in questions array
                    // ordinal inserted based on the index of question in the array
                    textField.text = (questions.indexOf(q) + 1) + ". " + q.question;
                    // change nextX
                    nextX += textField.width;
                    // add field to display list
                    addChild(textField);
                    // add text field to the object for future linkage to answer
                    // this step is optional because actual answer string will be used
                    q.questionText = textField;
                    // CREATE ANSWER input field
                    // note - the same variable textField is used again - NOT the same instance but different instance of THE SAME variable
                    textField = new TextField();
                    textField.defaultTextFormat = textFormat;
                    textField.border = true;
                    textField.width = 200;
                    textField.height = 20;
                    textField.type = TextFieldType.INPUT;
                    textField.x = 30;
                    textField.x = nextX;
                    textField.y = nextY;
                    // change nextX to accomodate feedback TextField
                    nextX += textField.width;
                    // add field to display list
                    addChild(textField);
                    // add text field to the object for future linkage to answer
                    q.answerText = textField;
                    // CREATE FEEDBACK field
                    // again - use the same textField variable to create new instances
                    textField = new TextField();
                    textField.defaultTextFormat = correctTF;
                    textField.width = 100;
                    textField.height = 20;
                    textField.x = nextX + 10;
                    textField.y = nextY;
                    // add field to display list
                    addChild(textField);
                    // add feedback field to the object for linkage to question
                    q.feedback = textField;
                    // reset positions defaults for the next loop iteration
                    nextX = 30;
                    nextY += textField.height + 10;
                    
                }
                
                checkButton.x = textField.x + textField.width;
                checkButton.y = textField.y + textField.height + 6;
                
                // assuming that button name is checkButton
                checkButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
            }
            
            private function drawcheckButton():void
            {
                // CREATE & ADD "SUBMIT" BUTTON
                
                checkButton = new Sprite(); //Create a new instance of a Sprite to act as the button graphic.
                checkButton.graphics.beginFill(0xFFCC00); //Set the color of the button graphic.
                checkButton.graphics.drawRect(0, 0, 100, 50); //Set X,Y, Width, & Height of button graphic.
                checkButton.graphics.endFill(); //Apply the fill
                
                checkButton.useHandCursor = true; //Add useHandCursor, buttonMode, & mouseChildren if required
                checkButton.buttonMode = true;
                checkButton.mouseChildren = false;
                addChild(checkButton); //Add Button Sprite to stage
                var textLabel:TextField = new TextField();
                textLabel.text = "Submit!";
                textLabel.x = 20;
                textLabel.y = 10;
                textLabel.selectable = false;
                checkButton.addChild(textLabel)
            
            }
            
            private function buttonClickHandler(e:MouseEvent):void
            {
                // reset score to 0
                score = 0;
                // loop through the objects in questions array and compare answers
                for each (var q:Object in questions)
                {
                    // remove spaces from answers in case user types the in the beginning and the end
                    q.answerText.text = String(q.answerText.text).replace(/^\s+|\s+$/, "");
                    // compare answers in lower cases
                    if (q.answer.toLowerCase() == q.answerText.text.toLowerCase())
                    {
                        // increment score by 1
                        score++;
                        TextField(q.feedback).text = "correct";
                        TextField(q.feedback).setTextFormat(correctTF);
                    }
                    else
                    {
                        TextField(q.feedback).text = "incorrect!";
                        TextField(q.feedback).setTextFormat(incorrectTF);
                    }
                }
                // display score feedback
                // note literal conditional syntax (score != 1 ? "s" : "") that adds "s" for plurals
                scoreFeedback.text = "Score: " + Math.round(score * 100 / questions.length) + "% (" + score + " question" + (score != 1 ? "s" : "") + " correct out of " + questions.length + " questions.)";
            }
        }
    }
    
     
    |
    Mark as:
  • Currently Being Moderated
    Sep 17, 2012 6:14 PM   in reply to donalall

    A little improvement.

     

    Button should be a separate class. See CustomButton class below. Also class Main_questions implements this button (also attached to this message)

     

     

    package
    {
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        import flash.text.TextField;
        import flash.text.TextFormat;
     
        public class CustomButton extends Sprite
        {
            private var label:String;
            // off state
            private var stateOff:Sprite;
            // mouse over state
            private var stateOver:Sprite;
     
            public function CustomButton(label:String = "Label")
            {
                this.label = label;
                init();
            }
     
            private function init():void
            {
                stateOff = drawState(0xFFCC00, 0xBB5E00);
                stateOver = drawState(0xFFE991, 0x8C4600);
     
                addChild(stateOver);
                addChild(stateOff);
     
                stateOver.visible = false;
     
                buttonMode = useHandCursor = true;
                mouseChildren = false;
     
                addEventListener(MouseEvent.MOUSE_OVER, onInteraction);
                addEventListener(MouseEvent.MOUSE_OUT, onInteraction);
     
            }
     
            private function onInteraction(e:MouseEvent):void
            {
                stateOff.visible = e.type == MouseEvent.MOUSE_OUT;
                stateOver.visible = e.type == MouseEvent.MOUSE_OVER;
            }
     
            private function drawState(fillColor:uint, color:uint):Sprite
            {
                // horizontal padding
                var hPadding:Number = 20;
                // vertical padding
                var vPadding:Number = 6;
     
                var labelText:TextField = new TextField();
                labelText.defaultTextFormat = new TextFormat("Verdana", 10, color);
                labelText.multiline = labelText.wordWrap = false;
                labelText.autoSize = "left";
                labelText.text = label;
                labelText.x = hPadding * .5;
                labelText.y = vPadding * .5;
     
                var s:Sprite = new Sprite();
                s.graphics.beginFill(fillColor);
                s.graphics.drawRoundRect(0, 0, labelText.width + hPadding, labelText.height + vPadding, 5);
                s.graphics.endFill();
     
                s.addChild(labelText);
     
                return s;
            }
     
        }
     
    }
    

     

     

     

    package
    {
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        import flash.text.TextField;
        import flash.text.TextFieldType;
        import flash.text.TextFormat;
     
        public class Main_questions extends Sprite
        {
            // use single object that acts as a data provider and links questions, answers and runtime object
            private var questions:Array;
            // DEFAULT TEXT FORMAT
            private var textFormat:TextFormat = new TextFormat("Verdana", 9);
            // correct feedback format
            private var correctTF:TextFormat = new TextFormat("Verdana", 9, 0x008000);
            // incorrect feedback format
            private var incorrectTF:TextFormat = new TextFormat("Verdana", 9, 0xDF0000);
     
            private var checkButton:Sprite;
            // text field that displays score feedback
            private var scoreFeedback:TextField;
            // answers score value
            private var score:int = 0;
     
            public function Main_questions():void
            {
                init();
            }
     
            private function init():void
            {
                drawcheckButton();
                initData();
                drawQuestions();
            }
     
            /**
             * This method inititate data and populates it with questions/answers
             */
            private function initData():void
            {
                questions = [];
                // questions
                var question:Array = ["What is the Capital of Ireland?", "What is the Capital of France?", "What is the Capital of Spain?", "What is the Capital of Malaysia?", "What is the Capital of New York?", "What is the Capital of California?"];
                // answers
                var answer:Array = ["Dublin", "Paris", "Madrid", "Kuala Lumpur", "Albany", "Sacramento"];
                for (var i:int = 0; i < question.length; i++)
                {
                    // push new object into questions array - this uses literal object instantiation notation {}
                    questions.push({question: question[i], answer: answer[i]});
                }
            }
     
            /**
             * This method draws text fields and adds them to their correcponding objects
             */
            private function drawQuestions():void
            {
                // use/recycle the same variable - it is more efficient
                var textField:TextField;
     
                scoreFeedback = new TextField();
                scoreFeedback.defaultTextFormat = textFormat;
                scoreFeedback.autoSize = "left";
                scoreFeedback.width = 400;
                scoreFeedback.height = 20;
                addChild(scoreFeedback);
     
                scoreFeedback.x = scoreFeedback.y = 30;
                // var to control x positions
                var nextX:Number = scoreFeedback.x;
                // var to control y position
                var nextY:Number = scoreFeedback.y + scoreFeedback.height + 20;
                // loop through questions and create textfileds
                // for each loop is faster than for loop
                // on each loop iteration object element is used from appropriate position on the array
                for each (var q:Object in questions)
                {
                    // CREATE QUESTION TextField
                    textField = new TextField();
                    textField.defaultTextFormat = textFormat;
                    textField.width = 300;
                    textField.height = 20;
                    textField.x = nextX;
                    textField.y = nextY;
                    // get question text from the object in questions array
                    // ordinal inserted based on the index of question in the array
                    textField.text = (questions.indexOf(q) + 1) + ". " + q.question;
                    // change nextX
                    nextX += textField.width;
                    // add field to display list
                    addChild(textField);
                    // add text field to the object for future linkage to answer
                    // this step is optional because actual answer string will be used
                    q.questionText = textField;
                    // CREATE ANSWER input field
                    // note - the same variable textField is used again - NOT the same instance but different instance of THE SAME variable
                    textField = new TextField();
                    textField.defaultTextFormat = textFormat;
                    textField.border = true;
                    textField.width = 200;
                    textField.height = 20;
                    textField.type = TextFieldType.INPUT;
                    textField.x = 30;
                    textField.x = nextX;
                    textField.y = nextY;
                    // change nextX to accomodate feedback TextField
                    nextX += textField.width;
                    // add field to display list
                    addChild(textField);
                    // add text field to the object for future linkage to answer
                    q.answerText = textField;
                    // CREATE FEEDBACK field
                    // again - use the same textField variable to create new instances
                    textField = new TextField();
                    textField.defaultTextFormat = correctTF;
                    textField.width = 100;
                    textField.height = 20;
                    textField.x = nextX + 10;
                    textField.y = nextY;
                    // add field to display list
                    addChild(textField);
                    // add feedback field to the object for linkage to question
                    q.feedback = textField;
                    // reset positions defaults for the next loop iteration
                    nextX = 30;
                    nextY += textField.height + 10;
     
                }
     
                checkButton.x = textField.x + textField.width;
                checkButton.y = textField.y + textField.height + 6;
     
                // assuming that button name is checkButton
                checkButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
            }
     
            private function drawcheckButton():void
            {
                // CREATE & ADD "SUBMIT" BUTTON
     
                checkButton = new CustomButton("Submit"); //Create a new instance of a Sprite to act as the button graphic.
                addChild(checkButton)
     
            }
     
            private function buttonClickHandler(e:MouseEvent):void
            {
                // reset score to 0
                score = 0;
                // loop through the objects in questions array and compare answers
                for each (var q:Object in questions)
                {
                    // remove spaces from answers in case user types the in the beginning and the end
                    q.answerText.text = String(q.answerText.text).replace(/^\s+|\s+$/, "");
                    // compare answers in lower cases
                    if (q.answer.toLowerCase() == q.answerText.text.toLowerCase())
                    {
                        // increment score by 1
                        score++;
                        TextField(q.feedback).text = "correct";
                        TextField(q.feedback).setTextFormat(correctTF);
                    }
                    else
                    {
                        TextField(q.feedback).text = "incorrect!";
                        TextField(q.feedback).setTextFormat(incorrectTF);
                    }
                }
                // display score feedback
                // note literal conditional syntax (score != 1 ? "s" : "") that adds "s" for plurals
                scoreFeedback.text = "Score: " + Math.round(score * 100 / questions.length) + "% (" + score + " question" + (score != 1 ? "s" : "") + " correct out of " + questions.length + " questions.)";
            }
        }
    }
    
     
    |
    Mark as:
  • Currently Being Moderated
    Sep 18, 2012 4:50 AM   in reply to donalall

    Here are updated classes that use new CustomButton class and visualize score.

     

    Note that QuestionLine.checkAnswer() method now returns score for each line so that it can be used in QuestionsContainer.checkAnswers() method.

     

    Classes that are not posted did not change.

     

     

    package
    {
        import flash.display.Sprite;
        import flash.events.MouseEvent;
        
        public class MainQuestions extends Sprite
        {
            
            // container that displays questions
            private var container:QuestionsContainer;
            private var checkButton:CustomButton;
            public function MainQuestions():void
            {
                init();
            }
            
            private function init():void
            {
                // instnatiate container
                container = new QuestionsContainer(new QuestionsData());
                addChild(container);
                container.x = container.y = 30;
                checkButton = new CustomButton("Submit"); //Create a new instance of a Sprite to act as the button graphic.
                addChild(checkButton)
                // reposition button to the bottom right
                checkButton.x = container.x + container.width - checkButton.width;
                checkButton.y = container.y + container.height + 20;
                checkButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);
            }
            
            private function buttonClickHandler(e:MouseEvent):void
            {
                container.checkAnswers();
            }
        
        }
    }
    

     

     

     

    package
    {
        import flash.display.Sprite;
        
        public class QuestionsContainer extends Sprite
        {
            private var data:QuestionsData;
            // array of question lines
            private var qLines:Array;
            // maximum width of question field among all question lines used
            private var maxQWidth:Number = 0;
            // text field that displays score feedback
            private var scoreFeedback:QuestionTextFiled;
            // answers score value
            private var score:int = 0;
            
            public function QuestionsContainer(data:QuestionsData)
            {
                this.data = data;
                init();
            }
            
            private function init():void
            {
                // draw score
                scoreFeedback = new QuestionTextFiled();
                //scoreFeedback.autoSize = "left";
                scoreFeedback.width = 400;
                scoreFeedback.height = 20;
                addChild(scoreFeedback);
                
                // instance of question line that is reused
                var qLine:QuestionLine;
                qLines = [];
                
                for (var i:int = 0; i < data.questions.length; i++)
                {
                    qLine = new QuestionLine(data.questions[i], i);
                    // add line to array for further processing
                    qLines.push(qLine);
                    // grab width if it is the largest one
                    maxQWidth = Math.max(maxQWidth, qLine.questionWidth);
                }
                // now that we know the widest line - we can place objects on display list
                placeQuestion();
            }
            
            /**
             * Places question lines on display list and sets largest width for even alignment
             */
            private function placeQuestion():void
            {
                // vertical distance between questions
                var gap:Number = 6;
                // used to set y
                var nextY:Number = scoreFeedback.height + gap;
                for each (var q:QuestionLine in qLines)
                {
                    addChild(q);
                    q.questionWidth = maxQWidth;
                    q.y = nextY;
                    nextY += q.height;
                }
            }
            
            public function checkAnswers():void
            {
                score = 0;
                // loop through the lines and invoke answer checking on them
                // read score of each line - method returns int
                for each (var q:QuestionLine in qLines)
                    score += q.checkAnswer();
                
                scoreFeedback.text = "Score: " + Math.round(score * 100 / data.questions.length) + "% (" + score + " question" + (score != 1 ? "s" : "") + " correct out of " + data.questions.length + " questions.)";
            }
        
        }
     
    }
    

     

     

     

    package
    {
        import flash.display.Sprite;
        import flash.text.TextFieldAutoSize;
        import flash.text.TextFieldType;
        import flash.text.TextFormat;
        
        public class QuestionLine extends Sprite
        {
            // text fields
            private var question:QuestionTextFiled, answer:QuestionTextFiled, feedback:QuestionTextFiled;
            // text formats
            private var correctFormat:TextFormat = new TextFormat("Verdana", 9, 0x008000);
            private var incorrectFormat:TextFormat = new TextFormat("Verdana", 9, 0xDF0000);
            // x gap between fields
            private var gap:Number = 10;
            // related to question data
            private var data:Object;
            // question ordinal
            private var index:int = 0;
            // row background colors
            private var rowColors:Array = [0xE8E8E8, 0xFFFFFF];
            // internal padding
            private var padding:Number = 4;
            
            public function QuestionLine(data:Object, index:int)
            {
                this.data = data;
                this.index = index;
                init();
            }
            
            private function init():void
            {
                question = new QuestionTextFiled();
                answer = new QuestionTextFiled();
                feedback = new QuestionTextFiled();
                
                question.x = padding;
                question.y = answer.y = feedback.y = padding;
                
                answer.width = 150
                feedback.width = 60;
                
                question.autoSize = TextFieldAutoSize.LEFT;
                
                question.text = String(index + 1) + ". " + data.question;
                
                answer.type = TextFieldType.INPUT;
                
                addChild(question);
                addChild(answer);
                addChild(feedback);
            }
            
            /**
             * Provides width of the question field - used for even alignment of
             * textfields in other instances.
             */
            public function get questionWidth():Number
            {
                return question.width;
            }
            
            /**
             * Used to even up fields
             */
            public function set questionWidth(value:Number):void
            {
                // reset autosize so that we can set precise width
                question.autoSize = TextFieldAutoSize.NONE;
                question.width = value;
                // reposition other fields to accomodate passed value
                answer.x = question.x + question.width + gap;
                feedback.x = answer.x + answer.width + gap;
                // draw background based on whether index is odd or even
                graphics.beginFill(rowColors[index % 2]);
                graphics.drawRect(0, 0, width + padding * 2, height + padding * 2);
                // draw buttom line - mainly for the cases when background is white 
                // so there is always line that separates the instance visually
                graphics.lineStyle(1, rowColors[1 - index % 2]);
                graphics.moveTo(0, height);
                graphics.lineTo(width, height);
            }
            
            /**
             * Validates user entry and compare entry with the correct answer
             */
            public function checkAnswer():int
            {
                // validate entries
                // remove leading and double spaces
                answer.text = answer.text.replace(/^\s+|\s+$/, "").replace(/\s{2,}/g, " ");
                if (answer.text.toLowerCase() == data.answer.toLowerCase())
                {
                    feedback.text = "correct";
                    feedback.setTextFormat(correctFormat);
                    // make it proper
                    answer.text = data.answer;
                    return 1;
                }
                else
                {
                    feedback.text = "incorrect!";
                    feedback.setTextFormat(incorrectFormat);
                }
                
                return 0;
            }
        
        }
     
    }
    
     
    |
    Mark as:
  • Currently Being Moderated
    Sep 18, 2012 8:14 AM   in reply to Andrei1

    Hi Andrei1

    I tried this code (hoping it be useful for problem I'm having with flashcards arrays)  but even though I have made a button called checkButton - name, Class and instance  - I get this error:

    "1046: Typwewas not found or was not a compile-time constant: checkButton".

     

    I even added:

     

    import flash.display.SimpleButton;

     

    to the code, but it didn't help. What have I done wrong?Any advice much appreciated. Thanks .

    
     
    |
    Mark as:
  • Currently Being Moderated
    Sep 18, 2012 8:18 AM   in reply to athniel

    In my post No 27 there is a Class CustomButton. You must place this class into the same directory as your FLA and all other classes.

     
    |
    Mark as:
  • Currently Being Moderated
    Sep 20, 2012 1:14 AM   in reply to Andrei1

    Thanks. I removed my button and used your updated classes - all seems to be fine now.

     
    |
    Mark as:
  • Currently Being Moderated
    Sep 23, 2012 9:59 AM   in reply to donalall

    You are welcome.

     
    |
    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (1)

Answers + Points = Status

  • 10 points awarded for Correct Answers
  • 5 points awarded for Helpful Answers
  • 10,000+ points
  • 1,001-10,000 points
  • 501-1,000 points
  • 5-500 points