Tutorial: Flash XML using attributes



Tutorial: Flash XML using attributes

This is a description of a very silly application: information is read in from an xml file and used to produce bouncing pictures on the screen. The application grew ('like Topsy') as I wanted to demonstrate the use of different features, including xml attributes and xml subnodes that may or may not be present as well as manipulation of text fields. The example does not give a good model for organizing: the xml data listing family photos should not include specification of the horizontal and vertical speeds. Though my first version of the application used a specific xml file (this is sometimes described as hard-coding the name), the version shown here requires the viewer to type in the name of a file. I added very basic error handling for two conditions: the file named not existing and the file being badly formed xml.

Application

The application starts by presenting the viewer with an input text field to type in the name of the xml file. I refer to it as an album file.

[pic]

If the file named does not exist (this is termed an ioerror where io stands for input output), the program generates a text field indicating the error and then lets the player try again. Similarly, if the xml in the file had errors, the code generates a text field with the error message:

[pic]

Notice that checking out a missing file just requires making up a name of a file that doesn't exist. Checking the behavior for badly formed xml required creation of a file with badly formed xml!

If the file exists and is formed properly (see samples below), then images appear and start moving. Since this is an application with animation, screen shots do not give the full picture. There are 4 images bouncing around the screen along with information on each picture.

[pic]

I added numbers on the moving images and numbers on the titles. Certain pictures come with extra information.

Viewer input

Obtaining viewer input was trickier than I anticipated. In the other examples in which my applications use player input, bouncing ball and cannonball, I did not use addEventListener for a specific event. Instead, other factors determined when the code would extract the text from the input text field. For this application, I needed an event that would signal that the viewer had typed in a file name. The CHANGE event was NOT what I wanted: this event occurs with each keystroke. Instead, the event that works for this application is ComponentEvent.ENTER.

XML, attributes and subnodes

Previous tutorials have described reading in an xml file and then using the information to read in more files (other xml files and image files). The coding here is very similar. Code in the frame of the .fla file reads in the designated xml file. The code constructs a Movingsnapshot object by invoking its constructor method using data from the xml file. The constructor method loads an image and creates a text field that is part of the object. A Timer is created to animate the object. The function that handles the timing event moves the object horizontally and vertically using values passed in to the constructor method and stored as object variables.

The frame code invoking Movingsnapshot also creates and displays text information along with each image. The text information includes, at a minimum, a title for each image.

The previous tutorials involved xml files in which each subtree was identical. There also were no attributes. I decided to set up a situation in which there could be attributes and also different subnodes. Here is one xml file.

picnic3.jpg

Party in Ithaca

three.jpg

Celebrating thesis defense

This was about 3 months after the graduation ceremony.

emcoreydog.jpg

Esther, Corey and the dog

danielliam.jpg

Election Night

Daniel holding Liam

Attribute values can be extracted using the attribute method. In the code below, you will see

for each (var prop:XML in myXML.item) {

xs = Number(prop.attribute("xspeed"));

ys = Number(prop.attribute("yspeed"));

The .attribute (attribute name) method produces a null value if the attribute is not present. The Number function is necessary to convert the text to a number. Applying Number converts a null value to zero. This is exactly what I wanted in this situation. In others, you will need to do something like:

if (prop.attribute("xspeed")) { }

This is the approach I used for the 'extra' information in the comment or explain nodes.

My objective for the comment or the explain was to display this extra information when it was present. The critical coding was:

if (prop.hasOwnProperty("explain"))

This method returns true or false. When it is true, the true-clause uses the property. I do the same thing with the contents of elements as with elements.

Adding to the display list

Material created by ActionScript during runtime as opposed to creation using Flash authoring must be added to the display list. This is done using the addChild method. The moving image consists of the loaded jpg image along with a small text field holding the number. In my first try at implementing this, my code created the num text field before the image was loaded. This meant that the image was on top of it! The proper way to do this was to put the code for the text field for the number in the event handler function for when the image is loaded.

Implementation

The application consists of coding in the first frame and in a package called familyscenes. There is one class definition: Movingsnapshot.

The .fla file contains a static text field with the content: Family photos. Open up Window/Component and drag TextInput to the Stage. Give it the name albumname. On the Properties panel, click Parameters, and put in the text:

[pic]

The rest of the material is generated by coding. Some of it is in the first and only frame and some in the Movingsnapshot.as file. The code in the frame in outline is the following:

import statements

global variables: myXML, XML_URL,myXMLURL, myLoader

statement setting up response to viewer entering a name:

albumname.addEventListener(ComponentEvent.ENTER,getalbumname);

function definitions:

getalbumname

xmlLoaded

ioErrorHandler

WARNING: I give the code in outline so you can think about what it is before plunging into the details. Do not copy and paste the outline into your code.

The complete code, with explanations, follows:

|import familyscenes.*; |Import programmer package |

|import flash.text.*; | |

|import fl.controls.TextInput; | |

|import fl.ponentEvent; | |

|import flash.events.*; | |

| | |

|var myXML:XML = new XML(); |Will hold the parsed XML |

|var XML_URL:String ; |name of file |

|var myXMLURL:URLRequest; |For doing this request |

|var myLoader:URLLoader; |the URLLoader object |

|var ef:TextField = new TextField(); |Used for errors. Not visible if no errors.|

|albumname.addChild(ef); |add the text field for errors to display |

| |list as child of the text input field. |

| |This means all positioning in terms of |

| |that object |

|ef.x = 200; |position ef |

|ef.y = 100; |position ef |

|ef.width = 200; |adjust width |

|ef.height = 30; |adjust height |

|ef.border = true |Give field a border to stand out more |

|ef.visible = false; |Set to not be visible for now |

| | |

|albumname.addEventListener(ComponentEvent.ENTER,getalbumname); |Sets up handling of the viewer input |

|function getalbumname(ev:Event):void { |Called when viewer types in a file name |

| |AND presses enter |

|XML_URL = albumname.text; |Extract name of file |

|myXMLURL = new URLRequest(XML_URL); |set up request |

|myLoader = new URLLoader(myXMLURL); |set up URLLoader |

|myLoader.addEventListener("complete", xmlLoaded); |set up handling when loading is complete |

|myLoader.addEventListener(IOErrorEvent.IO_ERROR,ioErrorHandler); |set up handling if there is an io error |

| |(namely, no file found) |

|albumname.visible = false; |make input text box invisible |

|albumname.removeEventListener(ComponentEvent.ENTER,getalbumname); |stop event handling |

|ef.visible = false; |Make sure the text field for errors is not|

| |visible |

|} |close function |

| | |

|function xmlLoaded(event:Event):void { |called when xml file is loaded |

| try { |Just in case there are problems with the |

| |xml, put most of code in a try clause |

| myXML = XML(myLoader.data); |parse the file to set up the xml |

| var xs:int; |will hold designated horizontal speed |

| var ys:int; |will hold designated vertical speed |

| var ctr:int = 0; |hold count of images |

| var txstart:int = 260; |starting horizontal position of titles |

| var tystart:int = 100; |starting vertical position. This gets |

| |incremented |

| var tformat:TextFormat = new TextFormat(); |Format for titles |

| tformat.size = 20; |…. set size |

| tformat.color = 0x0000FF; |… set color (blue) |

| var cformat:TextFormat = new TextFormat(); |Format for comment and explain |

| cformat.italic = true; |… set to be italic |

| cformat.size = 20; |… set size |

| cformat.color = 0xDD00CC; |… set color (mauve?) |

| | |

| for each (var prop:XML in myXML.item) { |Iterate over each item |

| | |

| xs = Number(prop.attribute("xspeed")); |extract the horizontal speed. Will be 0 if|

| |no such attribute |

| ys = Number(prop.attribute("yspeed")); |extract the vertical speed. Will be 0 if |

| |no such attribute |

| | |

| ctr++; |Increment counter. Note: first one will be|

| |1. |

| var firstscene:Movingsnapshot = new |Construct a Movingsnapshot |

|Movingsnapshot(1000,1000,prop.picname,xs,ys,hook); | |

| | |

| var ntitle:TextField = new TextField(); |Set up textfield |

| ntitle.defaultTextFormat = tformat; |Set the formatting |

| addChild(ntitle); |Add to display |

| ntitle.text = String(ctr)+"> "+ prop.title; |Make the title be the count and the |

| |information from the xml |

| ntitle.x = txstart; |position horizontally |

| ntitle.y = tystart; |position vertically |

| ntitle.width = 300; |adjust width |

| tystart +=30; |Increment y value for next time |

| if (prop.hasOwnProperty("explain")) { |If (and only if) there is an explain node |

| var ex:TextField = new TextField(); |Construct text field |

| ex.defaultTextFormat = cformat; |Set formatting |

| addChild(ex); |Add to display list |

| ex.text = prop.explain; |Set text from xml file |

| ex.x = txstart+20; |offset x positioning |

| ex.y = tystart; |set y positioning |

| tystart +=30; |Increment y value for next time |

| ex.width = 500; |Adjust width |

| } |Close if true clause |

| if (prop.hasOwnProperty("comment")) { |If (and only if) there is a comment node |

| var co:TextField = new TextField(); |Construct text field |

| co.defaultTextFormat = cformat; |Set formatting (choose to use the same |

| |format as explain case) |

| addChild(co); |Add to display list |

| co.text = ment; |Set text from xml file |

| co.x = txstart+20; |offset x positioning |

| co.y = tystart; |set y positioning |

| tystart +=30; |increment y for next time |

| co.width = 500; |adjust width |

| } |Close if true clause |

| } |Close for loop |

| } |Close try clause |

| catch(ev) { |Catch any errors |

| ef.text = "Badly formed xml file. Try again."; |Write error message into the ef text field|

| ef.visible = true; |Make ef visible |

| albumname.addEventListener(ComponentEvent.ENTER,getalbumname); |Set up event handling (again) for viewer |

| |to type in name |

| albumname.visible = true; |Make the input text box visible |

| } |Close catch clause |

|} |Close function |

|function ioErrorHandler(ev):void { |Function to handle io error |

| ef.text = "Couldn't find file. Try again."; |Write error message into the ef text |

| |field. |

| ef.visible = true; |Make ef visible |

| albumname.addEventListener(ComponentEvent.ENTER,getalbumname); |Set up event handling (again) for viewer |

| |to type in name |

| albumname.visible = true; |Make the input text box visible |

|} |Close function |

The file Movingsnapshot.as is located in a folder named familyscenes, which is in a folder named as3. The .fla file Publish/Settings Flash Settings points to the as3 folder. Note: in PCs, this needs to be at the top of the drive containing the .fla file. In MACs, the .fla file and the as3 folder can be in the same folder.

The Movingsnapshot class definition provides the code to set up an image with a number on top of it in the upper left corner that will move across the screen, moving vertically and horizontally as specified by the parameters to the constructor function Movingsnapshot. The outline for this file is

import statements

class definition: Movingsnapshot extends MovieClip

class variable: the counter variable keeping track of the number of objects created

object variables

constructor method definition

imageloaded method definition

movepicture method definition

NOTE: there is no error handling for a request to load an image file that does not exist! See the other tutorials for fixing this.

The code in the Movingsnalshop.as file is the following:

|package familyscenes{ |package header |

| import flash.display.*; | |

| import .URLRequest; | |

| import flash.utils.Timer; | |

| import flash.events.*; | |

| import flash.text.*; | |

| public class Movingsnapshot extends MovieClip { |class definition header. Note: it needs to|

| |be a subclass of MovieClip because of the |

| |properties used, e.g., x and y. |

| internal static var counter:int = 0; |One counter for all calls. Will be |

| |incremented so 1 is the first used |

| public var scenetimer:Timer; |Each object has a Timer |

| public var ldr:Loader; |Used for loading in jpg |

| internal var xspeed:int; |horizontal speed |

| internal var yspeed:int; |vertical speed |

| internal var stagew:int; |Used to do the bouncing |

| internal var stageh:int; |Used to do the bouncing |

| public var num:TextField; |Label image with its number |

| public function Movingsnapshot(wid:int,ht:int,picname:String,speedx:int, |Constructor function to make a new object |

|speedy:int,hook:MovieClip):void { | |

| var imageURLRequest:URLRequest = new URLRequest(picname); |For the file request |

| ldr = new Loader(); |for loading in jpg |

| ldr.load(imageURLRequest); |Start the load |

| ldr.contentLoaderInfo.addEventListener(PLETE,imageloaded); |Set up event handling for when loading is |

| |complete |

| xspeed = speedx; |Set the x speed |

| yspeed = speedy; |Set the y speed |

| stagew = wid; |Set width of stage |

| stageh = ht; |Set height of stage |

| hook.addChild(this); |Add to the display list using the |

| |parameter hook |

| num = new TextField(); |Create a new text field |

| counter++; |Increment counter |

| num.text=String(counter); |Set as value of text field |

| num.border = true; |Give it a border |

| num.width = 12; |Adjust width |

| num.height = 16; |Adjust height |

| num.backgroundColor = 0xFFFFFF; |Set backgroundColor for number label to be|

| |white |

| num.background = true; |Set that there is a background |

| } |End constructor method |

| function imageloaded(e:Event):void { |Function to handle set up when image is |

| |loaded |

| this.addChild(ldr); |Add the loaded content to the display list|

| this.addChild(num); |NOW add the number label |

| scenetimer=new Timer(50); |Construct a Timer |

| scenetimer.addEventListener(TimerEvent.TIMER,movepicture); |Set up event handling for the animation |

| scenetimer.start(); |Start the timer |

| | |

| } |Close method |

| public function movepicture(ev) { |Function for moving the object |

| this.x +=xspeed; |Increment the horizontal position (could |

| |be positively or negatively) |

| this.y +=yspeed; |Increment the vertical position (could be |

| |positively or negatively) |

| if (this.x>stagew) { |Check if off the stage on the right |

| xspeed *=-1; |…. reverse horizontal direction |

| } |Close if clause |

| if (this.xstageh) { |Check if lower than the stage |

| yspeed *=-1; |… reverse the vertical direction |

| } |Close if clause |

| if (this.y ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download