
Beginning ActionScript 2.0 2006
.pdf
Chapter 10
4.Update the ActionScript file to contain the following code:
var imageListListener:Object = new Object(); imageListListener.change = function(eventObject:Object)
{
loadImage(eventObject.target.selectedItem.data);
}
var zoomListener:Object = new Object(); zoomListener.change = function(eventObject:Object)
{
setZoom(eventObject.target.value);
}
var imageViewerListener:Object = new Object(); imageViewerListener.progress = function(eventObject:Object)
{
var bytesLoaded:Number = eventObject.target.getBytesLoaded(); var bytesTotal:Number = eventObject.target.getBytesTotal(); trace(“Image Viewer Progress: “+bytesLoaded+”/”+bytesTotal); if(bytesLoaded == -1)
{
loadImageError();
}
else
{
imageViewerProgress.setProgress(bytesLoaded, bytesTotal);
}
}
imageViewerListener.complete = function(eventObject:Object)
{
trace(“Image Viewer Complete”); imageViewerProgress._visible = false; setZoom(zoomStepper.value);
}
function init() : Void
{
// Send data to the image list component var imageArray:Array = new Array();
imageArray.push({data:”images/aStudyInTexture.jpg”, label:”A Study In Texture”});
imageArray.push({data:”images/buntzenWinter.jpg”, label:”Buntzen Winter”}); imageArray.push({data:”images/flowerInDetail.jpg”, label:”Flower In Detail”}); imageArray.push({data:”images/galianoSunset.jpg”, label:”Galiano Sunset”}); imageList.dataProvider = imageArray;
imageList.addEventListener(“change”, imageListListener);
//Setup for the progress bar component imageViewerProgress.mode = “manual”; imageViewerProgress._visible = false;
//Setup for the scrollable image viewer component imageViewerPane.scrollDrag = true;
258

Interacting with the User
imageViewerPane.addEventListener(“progress”, imageViewerListener); imageViewerPane.addEventListener(“complete”, imageViewerListener);
// Setup for the zoom stepper component zoomStepper.maximum = 400; zoomStepper.minimum = 25; zoomStepper.stepSize = 25; zoomStepper.value = 100;
zoomStepper.addEventListener(“change”, zoomListener);
}
function loadImage(imagePath:String) : Void
{
trace(“loading: “ + imagePath);
if (imagePath != “” && imagePath != undefined)
{
imageViewerPane.contentPath = “”; imageViewerPane.contentPath = imagePath; imageViewerProgress._visible = true;
imageViewerProgress.setProgress(0, 100);
}
}
function loadImageError() : Void
{
imageViewerProgress._visible = false; imageList.selectedIndex = null; imageViewerPane.contentPath = “”;
}
function setZoom(zoomValue:Number) : Void
{
imageViewerPane.content._xscale = zoomValue; imageViewerPane.content._yscale = zoomValue; imageViewerPane.invalidate();
}
init();
5.Save the file, return to the Macromedia Flash project file, and select Control Test Movie.
How It Works
You first create the event listener objects, beginning with one for the image list component:
var imageListListener:Object = new Object(); imageListListener.change = function(eventObject:Object)
{
loadImage(eventObject.target.selectedItem.data);
}
The listener defines a handler for the change event, which fires every time the user clicks a different list row. The event listener gets the image URL from the selected row’s data property and passes that to the loadImage() function.
259

Chapter 10
The listener is created for the zoom stepper component:
var zoomListener:Object = new Object(); zoomListener.change = function(eventObject:Object)
{
setZoom(eventObject.target.value);
}
Once again, a change event handler is defined, which fires every time a new zoom value is selected from the NumericStepper component, either from clicking the up or down arrows, or by typing in a new value and pressing Enter.
Notice that the code in these two event handlers is minimal. Part of the best practices for development is to make code as generic as possible. Rather than writing code directly in the event handlers to load and to zoom the image, that code is placed within the functions. This provides greater flexibility in working with events.
The image viewer listener object is created, and a progress listener is constructed to check to see how much of the image has loaded and whether there was an error in finding the image (this code is taken from the pre-loader examples earlier in the book):
var imageViewerListener:Object = new Object(); imageViewerListener.progress = function(eventObject:Object)
{
var bytesLoaded:Number = eventObject.target.getBytesLoaded(); var bytesTotal:Number = eventObject.target.getBytesTotal(); trace(“Image Viewer Progress: “+bytesLoaded+”/”+bytesTotal); if(bytesLoaded == -1)
{
loadImageError();
}
else
{
imageViewerProgress.setProgress(bytesLoaded, bytesTotal);
}
}
Once the image is loaded, some maintenance needs to be performed. The complete listener fires at the end of the image load, hiding the progress bar and scaling the image to match the scaling set in the zoom stepper component:
imageViewerListener.complete = function(eventObject:Object)
{
trace(“Image Viewer Complete”); imageViewerProgress._visible = false; setZoom(zoomStepper.value);
}
Next, the init() function is defined. For the most part this is the same function as in the preceding Try It Out exercise. The only code that has been added is to assign event listeners to the imageList and zoomStepper components:
260

Interacting with the User
function init() : Void
{
// Send data to the image list component var imageArray:Array = new Array();
imageArray.push({data:”images/aStudyInTexture.jpg”, label:”A Study In Texture”});
imageArray.push({data:”images/buntzenWinter.jpg”, label:”Buntzen Winter”}); imageArray.push({data:”images/flowerInDetail.jpg”, label:”Flower In Detail”}); imageArray.push({data:”images”, label:”Galiano Sunset”}); imageList.dataProvider = imageArray;
imageList.addEventListener(“change”, imageListListener);
//Setup for the progress bar component imageViewerProgress.mode = “manual”; imageViewerProgress._visible = false;
//Setup for the scrollable image viewer component imageViewerPane.scrollDrag = true;
//Setup for the zoom stepper component zoomStepper.maximum = 400; zoomStepper.minimum = 25; zoomStepper.stepSize = 25; zoomStepper.value = 100;
zoomStepper.addEventListener(“change”, zoomListener);
}
That’s all that is needed to actually implement the event listeners. The remaining code provides the actual functionality behind the application:
function loadImage(imagePath:String) : Void
{
trace(“loading: “ + imagePath);
if (imagePath != “” && imagePath != undefined)
{
imageViewerPane.contentPath = “”; imageViewerPane.contentPath = imagePath; imageViewerProgress._visible = true; imageViewerProgress.setProgress(0, 100);
clearInterval(intervalID);
intervalID = setInterval(checkProgress, 200);
}
}
The loadImage() function makes sure that the string passed in with the path to the image is not blank, starts loading the image, and sets up the progress bar. The two calls to contentPath are there so that any image already shown in the image viewer pane is cleared out first. The call to setInterval() starts a polling process to monitor the progress of the image loading. The call to clearInterval() makes sure that if this is interrupting a previous load, the previous polling process is stopped.
261

Chapter 10
If the image could not be found, some cleanup is performed. The selected row in the image list is deselected, the progress bar is hidden, and the image viewer pane is reset:
function loadImageError() : Void
{
imageViewerProgress._visible = false; imageList.selectedIndex = null; imageViewerPane.contentPath = “”;
}
The setZoom() function does the actual scaling of the image based on the percent scale value passed in, and the invalidate() call tells the component to redraw itself because the scroll bars need to be updated to properly reflect the new size of the re-sized image:
function setZoom(zoomValue:Number) : Void
{
imageViewerPane.content._xscale = zoomValue; imageViewerPane.content._yscale = zoomValue; imageViewerPane.invalidate();
}
Finally, the startup function is called:
init();
Attaching Multiple Listeners to Multiple Components
So far, all of the event handling you’ve seen uses a one-to-one mapping between the listener object and the component. Although the preceding example does show how one listener could be assigned to multiple checkboxes, it misses the real advantage of using listeners: Not only can you assign a listener to multiple components, you can assign multiple listeners to a single component.
Listeners work by a system of publishing and subscribing. In much the same way as many people can subscribe to a magazine, multiple objects can subscribe to the same event on the same component. Each time the addEventListener() method is called on a component, a new subscriber is added to that component’s subscriber list. Every time the component generates an event, it notifies each of its subscribers.
Figure 10-2 shows some additional functionality in the ongoing image viewer project. A second list component is added on the left to list basic video content. It gives you another source of events for your listeners.
As you add functionality to a project, you may find that the listener setup becomes more complex and harder to work with. Once (or preferably before) this happens, it’s a good idea to step back and take a look at whether you can better organize the listeners.
262

Interacting with the User
Figure 10-2
Organizing the Listeners
As you add functionality to an interface, you have to structure the code to best handle that functionality. You need to know how to best apply your listener objects to handle user input.
One possibility is to have one listener object for each component on the screen, giving you four listeners for the image viewer project. That works, and many people do it that way. But instead of thinking in terms of the components on the screen, consider the functionality you have, and then map that to the components that provide the functionality. In Figure 10-2, for example, you can divide the interface into two functional groupings: the media list menus (the two list boxes) and the media viewer area (the scroll pane and zoom box).
Take a look at what the listener structure for that setup might look like:
var mediaListListener:Object = new Object(); mediaListListener.change = function(eventObject:Object)
{
// Handler code
}
imageList.addEventListener(“change”, mediaListListener); movieList.addEventListener(“change”, mediaListListener);
var mediaViewerListener:Object = new Object(); mediaViewerListener.change = function(eventObject:Object)
{
// Handler code
}
imageList.addEventListener(“change”, mediaViewerListener); movieList.addEventListener(“change”, mediaViewerListener); zoomStepper.addEventListener(“change”, mediaViewerListener);
263

Chapter 10
This has two listener objects: one for managing the menu and one for managing the media viewer area. Both objects subscribe to the change event of both list components. It looks like there’s not much separation between the two functional areas, but consider what the event handlers need to do. The menu handler’s job is basically to ensure that when something from one list is selected, the other list has nothing selected. That’s it.
The media viewer listener subscribes to the image list and the movie list components because it needs to know when to load new content. Once it gets that event, it operates as a self-contained unit that loads, zooms, and unloads content.
Handling Events from Multiple Sources
The functional listener structure could work, but there’s a small problem. The event that is of interest in all of the components is change. You have just one click handler in each listener object, so how do you know which component generated the event?
Fortunately, there is an easy way to deal with that. It is not listed within the component documentation, but every object in Flash that has an instance name also has a _name property that you can use to retrieve the instance name. You have a handle to the calling component via the event target property, so the following gets the name of the component generating the event:
var mediaListListener:Object = new Object(); mediaListListener.change = function(eventObject:Object)
{
trace(“Instance name: “ + eventObject.target._name);
}
imageList.addEventListener(“change”, mediaListListener); movieList.addEventListener(“change”, mediaListListener);
You can use the same listener now to handle events from both an image list component and a movie list component:
var mediaListListener:Object = new Object(); mediaListListener.change = function(eventObject:Object)
{
if (eventObject.target._name == “imageList”)
{
// Deselect anything selected in movieList
}
else if (eventObject.target._name == “movieList”)
{
// Deselect anything selected in imageList
}
}
imageList.addEventListener(“change”, mediaListListener); movieList.addEventListener(“change”, mediaListListener);
264

Interacting with the User
Similarly, you can create a media viewer listener that can listen for events from an image list component, a movie list component, and the zoom stepper:
var mediaViewerListener:Object = new Object(); mediaViewerListener.change = function(eventObject:Object)
{
if (eventObject.target._name == “imageList”)
{
// Load an image
}
else if (eventObject.target._name == “movieList”)
{
// Load a movie
}
else if (eventObject.target._name == “zoomStepper”)
{
// Set the content area scaling
}
}
imageList.addEventListener(“change”, mediaViewerListener); movieList.addEventListener(“change”, mediaViewerListener); zoomStepper.addEventListener(“change”, mediaViewerListener);
You now have a blueprint for how to manage each component’s events. Try this out on the image viewer application.
Try It Out |
Organizing Events for the Image Viewer Project |
In this exercise, you add a list component to the interface. You also modify the event listener objects so that they better separate units of functionality. Here are the steps:
1.Open the completed tryItOut_scriptingComponents.fla file from the first Try It Out exercise, or open tryItOut_scriptingComponents.fla from the book’s source files at <source file directory>/Chapter 10/tryItOut_scriptingComponents_v3/.
2.Copy the <source file directory>/Chapter 10/tryItOut_scriptingComponents_v3/movies directory (not just the directory contents) into the directory containing your .fla and .as files.
3.Click the image list component on the stage to select it. Open the Properties panel and change the height to 120 pixels.
4.Open the Components panel’s User Interface section and drag a new List component to the stage. Change its properties to x: 18, y: 30, width: 150, and height: 120.
5.Drag a new Label component to the stage. Set its x and y values to 18 and 208 pixels, respectively. Switch to the Parameters tab in the Properties panel and set the text parameter to Movie List.
6.Save the file.
265

Chapter 10
7.Open the completed tryItOut_scriptingComponents.as file from the first Try It Out exercise, or open tryItOut_scriptingComponents.as from the book’s source files at <root TBD>/Chapter 5/tryItOut_scriptingComponents_v3/.
8.Update the ActionScript file so that it looks like this:
//Handle the appearance of the list components
var mediaListListener:Object = new Object(); mediaListListener.change = function(eventObject:Object)
{
if (eventObject.target._name == “imageList”)
{
movieList.selectedIndex = null;
}
else if (eventObject.target._name == “movieList”)
{
imageList.selectedIndex = null;
}
}
//Zoom listener removed
//Handle changes to the main content area
var mediaViewerListener:Object = new Object(); mediaViewerListener.change = function(eventObject:Object)
{
if (eventObject.target._name == “imageList”)
{
loadMedia(eventObject.target.selectedItem.data, “image”);
}
else if (eventObject.target._name == “movieList”)
{
loadMedia(eventObject.target.selectedItem.data, “video”);
}
else if (eventObject.target._name == “zoomStepper”)
{
setZoom(eventObject.target.value);
}
}
mediaViewerListener.progress = function(eventObject:Object)
{
var bytesLoaded:Number = eventObject.target.getBytesLoaded(); var bytesTotal:Number = eventObject.target.getBytesTotal(); trace(“Image Viewer Progress: “+bytesLoaded+”/”+bytesTotal); if(bytesLoaded == -1)
{
loadImageError();
}
else
{
266

Interacting with the User
mediaViewerProgress.setProgress(bytesLoaded, bytesTotal);
}
}
mediaViewerListener.complete = function(eventObject:Object)
{
trace(“Image Viewer Complete”); mediaViewerProgress._visible = false; setZoom(zoomStepper.value);
}
function init() : Void
{
// Send data to the image list component var imageArray:Array = new Array();
imageArray.push({data:”images/aStudyInTexture.jpg”, label:”A Study In Texture”});
imageArray.push({data:”images/buntzenWinter.jpg”, label:”Buntzen Winter”}); imageArray.push({data:”images/flowerInDetail.jpg”, label:”Flower In Detail”}); imageArray.push({data:”images/galianoSunset.jpg”, label:”Galiano Sunset”}); imageList.dataProvider = imageArray;
imageList.addEventListener(“change”, mediaListListener); imageList.addEventListener(“change”, mediaViewerListener);
//Send data to the movie list component var movieArray:Array = new Array();
movieArray.push({data:”movies/animation.swf”, label:”Animation”}); movieArray.push({data:”movies/snowStorm.swf”, label:”Snow Storm”}); movieList.dataProvider = movieArray; movieList.addEventListener(“change”, mediaListListener); movieList.addEventListener(“change”, mediaViewerListener);
//Setup for the progress bar component
mediaViewerProgress.mode = “manual”; mediaViewerProgress._visible = false;
//Setup for the scrollable media viewer component mediaViewerPane.scrollDrag = true; mediaViewerPane.addEventListener(“progress”, mediaViewerListener); mediaViewerPane.addEventListener(“complete”, mediaViewerListener);
//Setup for the zoom stepper component
zoomStepper.maximum = 400; zoomStepper.minimum = 25; zoomStepper.stepSize = 25; zoomStepper.value = 100;
zoomStepper.addEventListener(“change”, mediaViewerListener);
}
function loadMedia(mediaPath:String, type:String) : Void
{
trace(“loading: “ + mediaPath);
if (mediaPath != “” && mediaPath != undefined)
{
mediaViewerPane.contentPath = “”;
267