Page 2. Creating CheckBoxes at Run-time

The application below shows a fully functioning checkbox quiz. Note that the structure we set up on the stage works as we proposed, but the content (title text, question text, and answer choices) are created at run-time. We will see that setting up checkboxes is very similar to setting up radio burttons that we saw presented in An XML-based RadioButton Quiz in Flash CS3.

As a user interface component, checkboxes differ from radiobuttons in that more than one checkbox can be chosen at any given time. This difference causes one significant change in our code: the correct answers and user answers must be stored in arrays rather than as single variables.

The Code

The following classes must be imported, and in addition the library must contain the CheckBox class. If you add a check box to the stage and then delete it, it will persist in the library.

import fl.controls.CheckBox;

For ease of positioning and clearing problems, we create a "question holder" on which the question text and answer components will be placed.

var qHolder:MovieClip = new MovieClip();

qHolder.x = 30;

qHolder.y = 60;

addChild(qHolder);

The following variables control the size of questions and answers, including the font color and font size for the questions. This information can be specified in an external xml file as well.

var qHeight:Number = 50;

var qWidth:Number = 500;

var aHeight:Number = 30;

var aWidth:Number = qWidth;

var qSize:Number = 16;

var qColor:uint = 0x000000;

Set the title for the quiz within the script so that this can be generalized as we move toward xml data on remaining pages of this tutorial.

txtTitle.text = "History Quiz";

We create an array containing the two questions in this quiz:

var arrQuestion:Array = [ "How invented calculus?", "Which of the following has never been the (common English) name of a pope?"];

We use an array of two arrays, each containing the answer choices for the respective questions:

var arrAnswers:Array = [["Archimedes","Euclid","Newton","Euler","Leibniz"],

["Leo","Benedict","Arnold","Urban","Mary","Michael"]];

We need an array containing the correct answers to the two questions. Since there can be more than one correct answer to each question, we simply use a 0-1 array to hold information about whether each choice is correct (1) or incorrect (0). Hence, the length of the arrays in arrCorrect must match the number of answers for the respective questions.

var arrCorrect:Array = [[0,0,1,0,1], [0,0,1,0,1,1]];

We create a 0-1 array containing the indices of the user answers, initialized to [0,0,...,0], so that initially the user sees all unchecked boxes.

var arrUserAnswers:Array = [[0,0,0,0], [0,0,0,0]];

We create a 0-1 array to signal that a question has the correct answer selected as well as variables for the number of questions for this set and for an "index" for the current question:

var arrDone:Array = [0,0];

var numExamples:int = arrQuestion.length;

var index:int = 0;

var arrChoices:Array;

The setup function removes the old question and answers, and adds current questions and answers as children to qHolder. This is the heart of the script.

function setup():void {

var j:int;

/*

Since qHolder has no children other than questions and answers, we remove all of its children to clear the previous question.

*/

while (qHolder.numChildren > 0) {

qHolder.removeChild(qHolder.getChildAt(0));

}

// Update problem counter and clear feedback for the new problem.

txtCounter.text = "Problem " + String(index+1) + " of " + String(numExamples) + ".";

txtFeedback.text = "";

 

/*

The format of the question is set inside of the setup function in case the user wants to add the ability to handle custom formatting for individual questions in the same problem set.

*/

var qFormat:TextFormat = new TextFormat('Arial',qSize,qColor);

 

/*

We build the text field according to specified parameters and add it as a child of qHolder.

*/

var qField:TextField = new TextField();

qField.width = qWidth;

qField.height = qHeight;

qField.x = 0;

qField.y = 0;

qField.multiline = true;

qField.wordWrap = true;

qHolder.addChild(qField);

 

// Set the format and content of the textfield.

qField.defaultTextFormat = qFormat;

qField.text = String(index+1) + ". " + arrQuestion[index];

 

// Make the "check" visible if this question has already been answered correctly.

if (arrDone[index] == 1) {

mcCheck.visible = true;

}

else {

mcCheck.visible = false;

}

 

// Set up the checkboxes with appropriate characteristics in an array.

arrChoices = new Array(arrAnswers[index].length);

for (j=0; j<arrAnswers[index].length; j++) {

arrChoices[j] = new CheckBox();

arrChoices[j].label = arrAnswers[index][j];

arrChoices[j].width = qField.width;

arrChoices[j].x = qField.x + 10;

arrChoices[j].y = qField.y + qHeight + (aHeight+5)*(j);

/*

Make the answers initially checked match the user's last answers for this question. If this question is being read for the first time, note that arrUserAnswers[index] is initialized as "all unchecked."

*/

if (arrUserAnswers[index][j] == 1) {

arrChoices[j].selected = true;

}

else {

arrChoices[j].selected = false;

}

arrChoices[j].addEventListener(MouseEvent.CLICK,updateAnswer);

qHolder.addChild(arrChoices[j]);

}

// Place the "CHECK" button beneath the group answers

btnCheck.x = qHolder.x + 10;

btnCheck.y = qHolder.y + qHeight + (aHeight +5)*(j);

}

Changing any CheckBox object will update the "user answer" array, but the answer is not not checked here.

function updateAnswer(mevt:MouseEvent):void {

for (var j=0; j<arrChoices.length; j++) {

if (arrChoices[j].selected) {

arrUserAnswers[index][j] = 1;

}

else {

arrUserAnswers[index][j] = 0;

}

}

}

This button checks the answer and updates the arrDone array as well as makes the check mark visible if the answer is correct.

btnCheck.addEventListener(MouseEvent.CLICK, chkAnswer);

function chkAnswer(mevt:MouseEvent):void {

var j:int;

var isCorrect:Boolean = true; // The user is correct until proven wrong!

 

// Check every checkbox to see if the user's answers match the correct answers.

for (j=0; j<arrChoices.length; j++) {

if (arrCorrect[index][j] != arrUserAnswers[index][j]) {

isCorrect = false;

}

}

 

// Respond appropriately to right or wrong answers.

if (isCorrect) {

txtFeedback.text = "CORRECT!";

arrDone[index] = 1;

mcCheck.visible = true;

}

else {

txtFeedback.text = "NO, TRY AGAIN.";

arrDone[index] = 0;

mcCheck.visible = false;

}

}

Next and Previous buttons simply step through the problems (referenced by "index") in a cycle.

btnNext.addEventListener(MouseEvent.CLICK, goNext);

function goNext(mevt:MouseEvent):void {

index++;

if (index > (numExamples - 1)) {

index = 0;

}

setup();

}

 

btnPrev.addEventListener(MouseEvent.CLICK, goPrev);

function goPrev(mevt:MouseEvent):void {

index--;

if (index < 0) {

index = numExamples - 1;

}

setup();

}

The "QUIT" button calls the finish function.

btnDone.addEventListener(MouseEvent.CLICK, donePressed);

function donePressed(mevt:MouseEvent):void {

finish();

}

We have created and linked in the library the EndClip movie clip containing a dynamic text box that we can write results into.

function finish():void {

var stMessage:String;

var mcFinal:EndClip = new EndClip();

var score:Number = 0;

mcFinal.x = 5;

mcFinal.y = 5;

addChild(mcFinal);

// The score is the number that are currently answered correctly.

for (var i=0; i<numExamples; i++) {

score += arrDone[i];

}

stMessage = "You got " + String(score) + " of " + String(numExamples) + " problems correct. Click anywhere to go back ";

stMessage = stMessage + "and work on them some more. Problems without a check mark are not answered correctly.";

mcFinal.txtReport.text = stMessage;

mcFinal.addEventListener(MouseEvent.CLICK, closePanel);

}

When the mcFinal clip is clicked, the mcFinal clip is removed entirely.

function closePanel(mevt:MouseEvent):void {

var mcFinal:MovieClip = mevt.currentTarget as MovieClip;

mcFinal.removeEventListener(MouseEvent.CLICK, closePanel);

removeChild(mcFinal);

setup();

}

 

setup();

Download

Download the well-commented fla file for the application shown above.

Back to Intermediate Tutorials              Back to Flash and Math Home

We welcome your comments, suggestions, and contributions. Click the Contact Us link below and email one of us.

Adobe®, Flash®, ActionScript®, Flex® are registered trademarks of Adobe Systems Incorporated.