How to Build a XML Driven Quiz Application in Flash
21
In this Flash tutorial, we will learn how to create XML quiz application in Flash using the basics we previously covered about working with XML and Flash. If you did not read the previous part of this article.
Related posts:
- Create Your First Android AIR App in Flash
- How to Create a Snake Game in Flash Using AS3
- Creating Reflection in Flash Using AS3
- Bitmap Data Manipulation in Flash ActionScript 3
- Creating and Controlling Flash Animation with XML
- Approach to Understand XML and Flash Workflow
you can check Approach to Understand XML and Flash Workflow to be able to follow up with the Flash tutorial.
Now its time to do something meaningful, which can be used right there in the outside world. After completing this tutorial you will be able to develop XML driven quiz application.
Step 1: Prepare XML for our quiz application
1) Create a folder ‘QuizData’.
2) Now create following XML file in your favourite text editor.
<?xml version=”1.0” encoding=”UTF-8”?>
<Quiz>
</Quiz>
Yes you are right, this is a root node
Save this file as ‘Quiz.xml’ in the same folder ‘QuizData’.
Add a node to the above XML file,
<Quiz>
<Question>
<QText>This is Question no.1. </QText>
</Question>
</Quiz>
Here we have added one question to our XML file. You can add more questions but for now it will work. Later we shall add good set of questions.
3) A quiz is incomplete without options with one right answer to choose from.
Let’s add options as follows,(Bold lines)
<Quiz>
<Question>
<QText>Q1.This is Question no.1. </QText>
<Option> Place here option no1 </Option>
<Option> Place here option no2 </Option>
<Option> Place here option no3 </Option>
</Question>
</Quiz>
Here we set a question with three options. For now we shall use this XML.
Step 2: Now it’s time for some Flashing
1) Create a new Flash Document for Action Script 3 and save it in the same folder ‘QuizData’ where you saved your xml file ‘Quiz.xml’.
2) Adjust stage size as 800 x 600.
3) Add dynamic text field (Arial, 20, bold) to the stage and place it at the top. Expand it enough as it is going to display your question. Give Instance name as ‘Question_TF’.
(Note: For CS5, embed font for action script.)
Step 3: Loading XML file
In this step we shall load XML file created in step1 to create XML document and access children form it.
Add following script to a first and only keyframe in a time line.
var url:URLRequest = new URLRequest(“Quiz.xml”); // url of xml file
var xmlLoader:URLLoader = new URLLoader(url); // xml file loader
//When xml file is completely loaded call ‘onXMLLoad’ function
xmlLoader.addEventListener(Event.COMPLETE, onXMLLoad);
//Create XML document and have access to its children
var xml:XML;
var xmlList:XMLList;
var xmlChildren;
function onXMLLoad(e:Event):void
{
xml = new XML(xmlLoader.data); //create XML document
xmlList = new XMLList(xml); //create XML List of XML nodes
xmlChildren = xmlList.children (); //Get number of child nodes
}
Step 4: Extracting question from XML
1) Continue with the above code. Our first task is to display the question in the TextField we have on the stage. How will we do that?
2) We shall add a new function ‘generateQuestion ()’ to our script as follows,
function generateQuestion (): void {
//Extract a question from xml file
}
Call this function inside ‘onXMLLoad’ function as shown below. (Bold line)
function onXMLLoad(e:Event):void {
xml = new XML(xmlLoader.data); //create XML document
xmlList = new XMLList(xml); //create XML List of XML nodes
xmlChildren = xmlList.children(); //Get number of child nodes
generateQuestion (); // This function extracts question from XML.
}
3) Make ‘generateQuestion ()’ function working as follows,
function generateQuestion (): void {
//Extract a question from xml file
Question_TF.text = xmlChildren.QText;
}
4) Modify it and get total number of questions. (used in coming steps)
var totalQuestions:Number;
function generateQuestion (): void {
Question_TF.text = xmlChildren.QText;
//get total number of questions
totalQuestions = xmlChildren.length();
}
(Note: For CS5 embed font for action script using properties panel for text field)
Press CTRL+ENTER (Win)/CMD+ENTER (Mac) to test it.
There it is! Our first question is nicely placed in the text field.
Step 5: Preparing radio buttons for options
Our second task is to display options below question. We shall use radio buttons for this purpose, as we are going to make objective test with single choice option.
To achieve this we need total number of options specified in XML file. So that we can decide how many radio buttons needs to be added to the stage below a ‘Question’.
1) Get total number of options for the current question as follows, (Bold lines)
var totalOptions: Number;
function generateOptions (): void {
//Get total number of options for the current question
totalOptions = xmlChildren.Option.length();
}
Call this function inside ‘generateQuestion()’ as shown, (Bold line)
function generateQuestion():void{
Question_TF.text = xmlChildren.QText;
totalQuestions = xmlChildren.length();
//create and place options below question
generateOptions();
}
2) Before creating and placing radio buttons we must have to do couple of things.
First add following lines to the start of the script,
import fl.controls.RadioButton;
import fl.controls.RadioButtonGroup;
Secondly, add radio button component to the library
(Drag radio button component directly to the library)
Or
(Drag it to the stage. So that it is available in the library. But here delete it from the stage after dragging because we are going to add them dynamically.)
3) To create and place radio buttons modify ‘generateOptions()’ function and add new vars to the script as follows, (Bold lines)
var totalOptions:Number;
var radioButton:RadioButton;//a radio button
var vPadding:uint = 0;//control the distance between radio buttons
var vSpacing:uint = 50;//provide equal space between radio buttons
function generateOptions():void{
//Get total number of options for the current question
totalOptions = xmlChildren.Option.length();
//Create radio buttons equal to the number of options of current question
for (var i:int = 0; i < totalOptions; i++) {
radioButton = new RadioButton(); // create radio button
addChild(radioButton); //add it to the stage
radioButton.x = Question_TF.x + 30; // adjust ‘x’ position
//Adjust ‘y’ position of radio buttons
radioButton.y = (vPadding + vSpacing) + (Question_TF.y + Question_TF.height);
vPadding += vSpacing;
}
}
Press CTRL+ENTER (Win) / CMD+ENTER (Mac) to test it.
Wow!!! See those radio buttons living on their floors.
But they are required to be filled with options specified in xml file. Perform next step.
Step 6: Adding options for a given question
Continue with above ‘for’ loop. Modify it as shown below (bold lines),
for (var i:int = 0; i < totalOptions; i++){
radioButton = new RadioButton();
addChild(radioButton);
radioButton.x = Question_TF.x + 30;
radioButton.y = (vPadding + vSpacing) + (Question_TF.y + Question_TF.height);
vPadding += vSpacing;
//Extract and add option form xml to radio button label
radioButton.label = xmlChildren.Option[i];
radioButton.width = 300; // for proper display of options
}
COOL!!! All radio buttons are displaying options extracted from xml file.
Step 7: Setting up a ‘correct’ answer
How to check whether the current selection is correct or incorrect answer?
Any Guess?
Hint: Use XML attributes.
This is the perfect situation where we can take the help of XML attribute.
1) Modify our ‘Quiz.xml’ file as shown (bold words)
<Quiz>
<Question>
<QText>Q1.This is Question no.1. </QText>
<Option> Place here option no1 </Option>
<Option correct =”1”> Place here option no2 </Option>
<Option> Place here option no3 </Option>
</Question>
</Quiz>
We have added XML attribute ‘correct = 1’. We shall use this attribute to set current option as a correct answer.
The logic behind this approach is simple. Consider following points,
a) Get an index number of the option (XML file) having attribute ‘correct = 1’.
i.e. <Option correct = “1”>
b) Get an index number of the selected radio button.
c) Compare these index numbers with each other. If they are equal, the answer is correct else it is incorrect.
2) So we have a new task now. Get the index number of the option having attribute ‘correct = 1’ in xml file. So modify the script as follows. (Bold lines)
var totalOptions:Number;
var radioButton:RadioButton;
var vPadding:uint = 0;
var vSpacing:uint = 50;
var isCorrect:Number;
var correctAnswerIndex:Number;
function generateOptions():void{
totalOptions = xmlChildren.Option.length();
for (var i:int = 0; i < totalOptions; i++){
radioButton = new RadioButton();
addChild(radioButton);
radioButton.x = Question_TF.x + 30;
radioButton.y = (vPadding + vSpacing) + (Question_TF.y + Question_TF.height);
vPadding += vSpacing;
radioButton.label = xmlChildren.Option[i];
radioButton.width = 300;
//Get the index of correct option(‘correct’ attribute) from xml file
isCorrect = xmlChildren.Option[i].@correct;
if(isCorrect == 1){
correctAnswerIndex = i; //this is the index no. of correct option
}
}
}
Our next target is to get an index number of selected radio button. But wait. It is not as straight forward as you think.
First we have to create a group of radio buttons to act as a single component.
Step 8: Grouping radio buttons
We shall group radio buttons. They will act as a single component. So we can use getRadioButtonIndex() method available with radio button group to get an index number of a selected radio button which is our next task.
Before that let us create a group of radio buttons as follows (Bold lines);
var totalOptions:Number;
var radioButton:RadioButton;
var radioButtonGroup:RadioButtonGroup;
var vPadding:uint = 0;
var vSpacing:uint = 50;
var isCorrect:Number;
var correctAnswerIndex:Number;
function generateOptions():void {
totalOptions = xmlChildren.Option.length();
radioButtonGroup = new RadioButtonGroup(“options”);
for (var i:int = 0; i < totalOptions; i++){
radioButton = new RadioButton();
addChild(radioButton);
radioButton.x = Question_TF.x + 30;
radioButton.y = (vPadding + vSpacing) + (Question_TF.y + Question_TF.height);
vPadding += vSpacing;
radioButton.label = xmlChildren.Option[i];
radioButton.width = 300;
radioButton.group = radioButtonGroup; //grouping radio buttons
isCorrect = xmlChildren.Option[i].@correct;
if(isCorrect == 1){
correctAnswerIndex = i;
}
}
}
Step 9: Get an index no. of selected radio button
This step is really important in terms of the approach we have attempted here to develop this XML driven quiz application.
This step will not only satisfy our second need of getting an index number of selected radio button but we are also adding a new function checkAnswer() to the script as follows,
var currentRadioButton;
var currentSelection;
function checkAnswer(e:MouseEvent):void {
currentRadioButton = e.currentTarget; // store selected radio button
//Get an index number of selected radio button
currentSelection = radioButtonGroup.getRadioButtonIndex(currentRadioButton));
}
Now that we have both index numbers as,
correctAnswerIndex (for XML option with attribute as <Option correct = ”1”>)
correctSelection (for selected radio button)
It is time to compare them with each other. Follow the next step
Step 10: Checking ‘correct’ answer
We cannot complete a quiz without checking the answer and displaying the result.
Our immediate goal is to achieve the same. How to do that?
We shall modify the checkAnswer (e: MouseEvent) function as shown, (Bold lines)
var currentRadioButton;
var currentSelection:Number;
var resultStr:String;
var result_TF:TextField = new TextField (); //to display result for current question
result_TF.width = 250; //for proper text display
addChild (result_TF); //add it to the stage
function checkAnswer(e:MouseEvent):void {
currentRadioButton = e.currentTarget; // store selected radio button
//Get an index number of selected radio button
currentSelection = (radioButtonGroup.getRadioButtonIndex(currentRadioButton));
//Check and store answer
resultStr = (currentSelection == correctAnswerIndex) ? “Correct” : “Incorrect”;
//Display a result
result_TF.text = resultStr;
//Positioning the result textfield
result_TF.x = radioButton.x + 30; //’x’ position
result_TF.y = (vPadding + vSpacing)+50; //’y’ position
}
If you test the movie and click radio buttons nothing will happen. Why? Follow next step.
Step 11: Responding to mouse click
To make radio buttons respond to mouse click, add following line (bold line) to ‘for’ loop of ‘generateOptions()’ function as shown,
for (var i:int = 0; i < totalOptions; i++){
radioButton = new RadioButton(); // create radio button
addChild(radioButton); //add it to the stage
radioButton.x = Question_TF.x + 30; // adjust ‘x’ position
//Adjust ‘y’ position of radio buttons
radioButton.y = (vPadding + vSpacing) + (Question_TF.y + Question_TF.height);
vPadding += vSpacing;
//Extract option from XML file and add it to radio button label
radioButton.label = xmlChildren.Option[i];
radioButton.width = 300; // for proper display of options
//Get the index of correct option already set in xml file
isCorrect = xmlChildren.Option[i].@correct;
if(isCorrect == 1){
correctAnswerIndex = i; //this is the index no. of correct option
}
radioButton.addEventListener(MouseEvent.CLICK, checkAnswer);
}
Test your movie.
Congrats!!! They are responding showing result. Now we are very close to the final version.
Step 12: Adding more questions
We were dealing with only one question up to this step. It’s time to add more fun to our ‘Quiz App’ by adding more questions thus satisfying the need ‘XML Driven’.
First modify our XML file ‘Quiz.xml’ as follows (Bold lines)
<?xml version=”1.0″ encoding=”UTF-8″?>
<Quiz>
<Question>
<QText> Q1. This is my first question. </QText>
<Option> Place here option no1 </Option>
<Option correct = “1”> Place here option no2 </Option>
<Option> Place here option no3 </Option>
</Question>
<Question>
<QText> Q2. This is my second question. </QText>
<Option correct = “1”> Place here option no1 </Option>
<Option> Place here option no2 </Option>
<Option> Place here option no3 </Option>
<Option> Place here option no4 </Option>
</Question>
<Question>
<QText> Q3. This is my third question. </QText>
<Option> Place here option no1 </Option>
<Option correct = “1”> Place here option no2 </Option>
</Question>
</Quiz>
I had intentionally placed different number of options for different questions. You can have your choice. (of number of questions and their number of options). Only take care of placing attribute ‘correct = “1”.
This was about XML. What about action script in Flash? We must modify it.
Step 13: Go to next question
This is the climax scene of our movie. So watch it carefully otherwise you will not be able to tell the story to others. Onwards you are going to see some important additions in the script those are essentially very important to make this quiz application ‘XML Driven’. So first read following points.
1) Introducing a new var currentQuestion:Number.
We shall utilize this var to point out (XML) index number of a question and so the related options going to be displayed on the stage.
Mostly we shall modify generateQuestion() and generateOptions() by replacing ‘xmlChildren’ with ‘xmlChildren[currentQuestion]’. See it soon.
2) And one more var radioButtonContainer:Movieclip.
This will hold all radio buttons of current question. And will help to remove those radio buttons from the stage and add new ones.
3) And last one for now i swear, var radioButtonArray:Array.
This will store radio buttons and will provide a reference of each radioButton to built in function ‘removeChild()’.
4) I know you are waiting for finishing touch. Please have patience. Face it.
There is also a new function ‘nextQuestion(e:MouseEvent)’ joining our family.
This is an important member of our family. It will open the door to meet the next question and its option.
Some part of the script is self explanatory. More focus on a logical part of it.
Don’t test the movie now. Do it after going through next step as we are also going to modify our ‘generateOptions()’ function by adding radioButtonArray.
First go through new function ‘nextQuestion(e:MouseEvent)’
//——– Go to next question ————————–
var currentQuestion:Number = 0; // reference to index number of question (XML file)
function nextQuestion(e:MouseEvent):void{
Question_TF.text = “”;
result_TF.text = “”;
//remove previous options
for (var i:int = 0; i < totalOptions; i++){
radioButtonContainer.removeChild(radioButtonArray[i]);
}
//check if current question is last question
if(currentQuestion < totalQuestions-1){
//next question index
currentQuestion++;
vPadding = 0;
totalOptions = 0;
radioButtonArray = [];
generateQuestion();
}
}
The var radioButtonArray:Array is still undefined. Go to next step.
Step 14: Push radio buttons into an array
Here we shall modify ‘generateOptions()’ function with the addition of ‘var radioButtonArray:Array’
We shall also add a var radioButtonContainer:Movieclip and replace addChild(radioButton) with radioButtonContainer.addChild(radioButton); in ‘generateOptions()’.
We shall also use ‘currentQuestion’ as xmlChildren[currentQuestion]. In our two functions i.e. generateQuestion() and generateOptions().
First modify ‘generateOptions()’
See it carefully, as shown below (Bold lines),
//—————— Create and place radio buttons below question —————————–
var totalOptions:Number;
var radioButton:RadioButton;
var radioButtonGroup:RadioButtonGroup;
var vPadding:uint = 0;
var vSpacing:uint = 50;
var isCorrect:Number;
var correctAnswerIndex:Number;
var radioButtonArray:Array;
var radioButtonContainer:MovieClip = new MovieClip();
addChild(radioButtonContainer);
function generateOptions():void{
radioButtonArray= new Array(); //Store radio buttons for reference
//Get total number of options for the current question
totalOptions = xmlChildren[currentQuestion].Option.length();
radioButtonGroup = new RadioButtonGroup(“options”);
for (var i:int = 0; i < totalOptions; i++){
radioButton = new RadioButton();
radioButton.selected = false;
//Previous addChild(radioButton) statement is replaced by following
radioButtonContainer.addChild(radioButton);
radioButton.x = Question_TF.x + 30;
radioButton.y = (vPadding + vSpacing) + (Question_TF.y + Question_TF.height);
vPadding += vSpacing;
radioButton.label = xmlChildren[currentQuestion].Option[i];
radioButton.width = stage.stageWidth;
radioButton.group = radioButtonGroup;
isCorrect = xmlChildren[currentQuestion].Option[i].@correct;
if(isCorrect == 1){
correctAnswerIndex = i;
}
radioButton.addEventListener(MouseEvent.CLICK, checkAnswer);
//push radio buttons into array for reference to removeChild()
radioButtonArray.push(radioButton);
}
}
Now modify generateQuestion(),
function generateQuestion():void{
//extract question from XML file
Question_TF.text = xmlChildren[currentQuestion].QText;
totalQuestions = xmlChildren.length();
generateOptions();
}
Finish next step and you are done with what you are expecting.
Step 15: Adding ‘Next’ button to the stage
Create a button (of your choice, I have added ‘arrow’ ) on the stage.
Give instance name as ‘nextButton’ to your button. Don’t worry about its position. We are going to handle it in a script.
After creating a button our next task is to make it functioning. Modify function checkAnswer(e:MouseEvent) as shown (Bold lines).
nextButton.visible = false;
var currentRadioButton;
var currentSelection:Number;
var resultStr:String;
var result_TF:TextField = new TextField ();
result_TF.width = 250;
addChild (result_TF);
function checkAnswer(e:MouseEvent):void {
currentRadioButton = e.currentTarget;
currentSelection = (radioButtonGroup.getRadioButtonIndex(currentRadioButton));
resultStr = (currentSelection == correctAnswerIndex) ? “Correct” : “Incorrect”;
result_TF.text = resultStr;
result_TF.x = radioButton.x + 30;
result_TF.y = (vPadding + vSpacing)+50;
//For correct answer ready to display next question
if(resultStr == “Correct”){
//check if current question is last question
if(currentQuestion < totalQuestions-1){
nextButton.visible = true;
nextButton.addEventListener(MouseEvent.CLICK, nextQuestion);
//next button position
nextButton.x = result_TF.x + result_TF.width + 40;
nextButton.y = result_TF.y;
}else{
result_TF.text = resultStr + ” —> Quiz Complete”;
}
}else
{
nextButton.visible = false;
nextButton.removeEventListener(MouseEvent.CLICK, nextQuestion);
}
}
This functions checks for correct answer. If answer is correct and the current question is not the last question then it displays ‘Next’ button on the stage. If answer is incorrect then it shows ‘Quiz Complete’ after result.
Good News!!!. Finally you can call it as XML driven quiz application.
Modify ‘Quiz.xml’ as per your need and experience the power of XML Driven.
If you wish you can stop here or you perform next step. I suggest the later one.
Step 16: Finally do some text formatting
Typography is an important part of any project (Digital or Non Digital). It really matters how text is handled.
We shall do some text formatting now. (Not great but will satisfy our need).
Our radio buttons labels are very poor. Make them more readable.
1) Add following lines at the start (below ‘import’ statements’) of the script
//Text formatting
var globalTextFormat:TextFormat = new TextFormat();
globalTextFormat.font = “Arial”;
globalTextFormat.size = 18;
globalTextFormat.bold = true;
//
2) To apply the above textformat to radio button labels, add following line into ‘for’ loop of ‘generateOptions()’ as shown (Bold line)
//Make radio button label more readable
radioButton.setStyle(“textFormat”,globalTextFormat);
3) We shall also apply this text format to result text field.
Important to say, that we are also making the text colour of result to change as per the answer. If answer is correct then result text will have ‘Green’ colour. And if answer is incorrect it will have ‘Red’ colour.
Modify function checkAnswer(e:MouseEvent) as shown (Bold lines).
var currentRadioButton;
var currentSelection:Number;
var resultStr:String;
var resultStrColor;
var result_TF:TextField = new TextField ();
result_TF.defaultTextFormat = globalTextFormat;
result_TF.width = 250;
addChild (result_TF);
function checkAnswer(e:MouseEvent):void {
currentRadioButton = e.currentTarget;
currentSelection = (radioButtonGroup.getRadioButtonIndex(currentRadioButton));
resultStr = (currentSelection == correctAnswerIndex) ? “Correct” : “Incorrect”;
result_TF.text = resultStr;
//Change text color of result as per answer (Green for correct and Red for incorrect)
resultStrColor = (resultStr == “Correct”) ? 0x009900 : 0xFF0000;
result_TF.textColor = resultStrColor;
result_TF.x = radioButton.x + 30;
result_TF.y = (vPadding + vSpacing)+50;
//……………rest of the code remains same ………….
}.
Nice Music Please!!! I am very much excited to say that we have finished our long journey to reach to see how to build ‘XML Driven Quiz Application’.
Conclusion
After completing this Flash tutorial you are able to develop any XML driven application. We also got opportunity to handle radio buttons. In the final section we did text formatting which will certainly help in your future work.
Since our goal was to learn to build ‘XML driven application’ we ignored beauty and styling of GUI. We were more focused on logical part. We also ignored scoring for the same reason. Now you know it is not that tough. I believe you can add it yourself. And you can improve it yourself. Thanks for your patience. Have a nice time and best of luck. Come back to see my more upcoming tutorials.
Thanks for this great tutorial
Great tutorial, thanks !
One of the most confusing tutorials I have ever tried to decipher. You include the same code over and over and people can’t keep up with what it’s actually supposed to look like.
How about putting only the NEW snippets and stating where they go. Also, a complete source example would EXTREMELY help to see where things went wrong.
Thanks for the note, I will mention this to the tutorial author.
Would there is somebody can teach me how to generate question from the xml randomly. (Base on this tutorial)
Thanks so much.
I am not sure if the author of the article is available, but I will ping him if he can help.
source file pls!!! i do something wrong, but i don’t know where…
Let me check with the author and ask him to send the source file and I will upload it to the tutorial page.
i have a problem.this is output error
TypeError: Error #1034: Type Coercion failed: cannot convert flash.display::SimpleButton@2cdf5fa1 to fl.controls.Button.
at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
at quiz_fla::MainTimeline()
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at quiz_fla::MainTimeline/frame1()
Thanks for the tutorial, its very good and simple to understand.
I am facing one issue facing an error at line
radioButtonContainer(radioButton); under function generateOptions()
it says Call to possibly undefined method radioButtonContainer.
Also can we add timer to this quiz so that it can skip to the next question after say 45 seconds and mark the answer as wrong. Also can we save the score may be in a text file along with the USERNAME of the system.
Hi. Thanks again
radioButtonContainer(radioButton)
the above error worked out, i added
radioButtonContainer.addChild(radioButton)
However i m receiving a warning that says
“5000: The class ‘fl.controls.Button’ must subclass ‘flash.display.SimpleButton’ since it is linked to a library symbol of that type.”
Can you please help me resolve this, Thanks again
Would like the downloadable example from it, thanks
Can there be a demo uploaded for this?
Sadly no, the author did not provide a demo for this.
pls.. I love dis tutorial.. bt it hs error.. pls let’s ensure workin examples are what are being used to illustrate on this site.. that’l help upcoming programmers like myself.. hope to get a working complete example of this tutorial
very thanks
This is a very helpful tutorial I’ve encountered in the net. Thanks for this great work. I will be more thankful if the questions can be generated randomly, and again if after a fixed number of seconds the unanswered question should be marked ‘unanswered’ and the program moves to the next question with a timer of course. I’ve tried to do this by myself but have not succeeded. I was able to improve on your work by adding a timer.
Must be var currentQuestion:Number=0; to fix some errors.
Admin what about Scoring ? 🙂 if you can help would be really great
Very confusing code. Something goes wrong when published
Now I understand the code. it works good. But I have to accumulate the code with great difficulty.