Thursday, November 5, 2009

Model View Controller

Model View Controller
The Model View Controller pattern is based on three elements named, you guessed it! Model, View and Controller. Also known as MVC, the Model View Controller pattern is a perfect fit for programming graphical interfaces. Which is a big part of Flash.

MVC strives to separate data from the interface that manipulates it. In this way it uncomplicates your process of programming many types of projects. The MVC pattern may seem to be complex at first. In reality it unravels the spaghetti mess of code that you often find yourself in when programming complex user interfaces.

This is a pattern that's built of other patterns. In particular, it relies heavily on the Observer pattern. If you haven't heard of the Observer pattern before don't worry, since it's built into AS3, as the Event Listener system. If you've added listeners and set up event handler (functions called by a listener), then you've already got EventDispatcher under your belt.

MVC Overview

The MVC pattern, as I mentioned earlier, is made up of three elements: Model, View and Controller. How these elements interact is the key to MVC pattern.

The Model only contains data. This can be as little as one value. The Model is not concerned with displaying anything, the View will handle this. The Model should never have a reference to the View or the Controller.

The View is the visual portion of the system. The goal of designing the View is making a class that will display data stored in the Model. Any system using MVC might have any number of Views working with a single Model.

The Controller passes information to the Model. Often Controllers are also Views.

The key to relationship between Model, View and Controller, is the View and Controller store a reference to the Model that they are working with. The Model should never have a reference to the View or Controller. The Model is only concerned with storing, processing and making data available to the View and Controller.

The glue that holds the Model, View and Controller together is the Event Listener system. The basic arrangement is that the View and Controller will register to receive CHANGE events from the Model. When the data in the Model changes the Model dispatches a CHANGE event. Model makes it's data available to the outside world via public methods.




Simple MVC Example
The following example illustrates the Model View Controller. The example creates a Model which stores an int as it's data. The View displays the Model's data in a TextField on the stage. The Controller creates two Buttons which increment and decrement the Model's data.

The Model
The Model will not be a display class but it will dispatch event messages. So we'll need to import the EventDispatcher class and extend EventDispatcher. Below is the basic class.

package {
    import flash.events.*;
    public class Model extends EventDispatcher {
        public function Model() {
           
        }
    }
}

The Model for this example stores only one simple piece of information. We'll use a private variable called _data for this:

private var _data:int;

Assign _data an initial starting value of 0 in the constructor of the class:

_data = 0;

Our goal is to allow the Controller to change the value of _data by increment and decrementing by one. To make this easy we'll make two public functions. Each of these functions will dispatch a CHANGE event to notify listeners that _data has been changed.

public function add_one():void {
    _data ++;
    dispatchEvent( new Event( Event.CHANGE ) );
}

public function subtract_one():void {
    _data --;
    dispatchEvent( new Event( Event.CHANGE ) );
}

Any controller or View class will need a way to access the _data inside of the Model. Since _data is a private var, in accordance with good OOP procedure, we can't access it directly. We'll set up a public function to make this available. This is an area where your Models may vary depending on the data they store. You could make many different functions that allow access to data in many different ways. For this example we'll have a simple function that returns an int.

public function get_data():int {
    return _data;
}

Here's the entire Model class for this example:

package {
    import flash.events.*;
    
    public class Model extends EventDispatcher {
        private var _data:int;
        
        public function Model() {
            _data = 0;
        }
        
        public function add_one():void {
            _data ++;
            dispatchEvent( new Event( Event.CHANGE ) );
        }
        
        public function subtract_one():void {
            _data --;
            dispatchEvent( new Event( Event.CHANGE ) );
        }
        
        public function get_data():int {
            return _data;
        }
    }
}




The View
The View class has the job of displaying information stored in the model. The View doesn't have to display the information literally it could display it in any form you care to invent. You can also create and each could display data from the model in a different way.

All of the Views will share some features in common. They will all probably extend one of the display classes like MovieClip or Sprite. They will all receive a reference to the Model as an argument of the Constructor function. They will all register for CHANGE events with the model.

Here's the basics of the class:

package {
    import flash.display.*;
    import flash.events.*;
    
    public class View extends Sprite {
        private var _model:Model;
        
        public function View( model:Model ) {
            _model = model;
            _model.addEventListener( Event.CHANGE, on_change );
        }
        
        private function on_change( e:Event ):void {
           
        }
    }
}

When you create an instance of the View it has a reference to the Model passed to it in the argument model. The View Class stores this in _model. The class then adds an event listener to _model listening for the CHANGE event. I created a handler for this listener named on_change. Since the Model will dispatch a CHANGE event whenever it's data changes our View will now be notified and can update itself.

To complete the View we'll add a TextField and we'll add a line of code to the on_change handler that sets the text of the TextField to display the value stored in the Model.


package {
    import flash.display.*;
    import flash.events.*;
    import flash.text.*;
    
    public class View extends Sprite {
        private var _model:Model;
        private var _txt:TextField;
        
        public function View( model:Model ) {
            _model = model;
            _model.addEventListener( Event.CHANGE, on_change );
            _txt = new TextField();
            addChild( _txt );
        }
        
        private function on_change( e:Event ):void {
            _txt.text = String( _model.get_data() );
        }
    }
}

Here's a quick rundown of the new elements.

First I imported the flash.text.* package. We need this since our class will work with the TextField.

Next I created a new private variable _txt to hold the TextField that we will create. In the constructor I created a new TextField and added it tothe display list.

Last I added a line to the on_change function that sets the text of _txt to the value of data stored in Model. We're calling the model's get_data method, and the Model is returning the int stored in Model's _data property. Since the text property of the TextField expects a String. I'm casting the value as String.

In this example I created the TextField via AS. This is not a requirement. You could also have used a clip from the library or referenced a clip on the stage. I used AS to create everything since that keeps all of the elements in code above.


The Controller
The controller will create two buttons that call the add_one and subtract_one  methods of the Model class. The controller can have many different manifestations. Often in Flash projects I find the controller is part of the View or part of the my main class.

In this example we'll make it a separate class. The class will extend Sprite, so that it will be a display object that appears on the stage.

As with the Model the Controller will take a reference to the Model as an argument of it's constructor function. This is the same as the View.

The Controller can also register with the Model to receive CHANGE events. This may or may not be needed it depends on what the does.

Here's the basic class for the view.

package {
    import flash.display.*;
    import flash.events.*;
    
    public class Controller extends Sprite {
        private var _model:Model;

        public function Controller( model:Model ) {
            _model = model;
        }
    }
}

For this example I will create two buttons with AS and add them to the stage. I'm creating the buttons via AS so that the example code here will contain all of the elements. You could easily use clips from your library instead if that fit your project better.

package {
    import flash.display.*;
    import flash.events.*;
    
    public class Controller extends Sprite {
        private var _model:Model;
        
        private var _up:Sprite;
        private var _down:Sprite;
        
        public function Controller( model:Model ) {
            _model = model;
            
            _up = new Sprite();
            _up.graphics.beginFill( 0x000000 );
            _up.graphics.drawRect( 0, 0, 22, 22 );
            _up.graphics.endFill();
            
            _down = new Sprite();
            _down.graphics.beginFill( 0x000000 );
            _down.graphics.drawRect( 0, 0, 22, 22 );
            _down.graphics.endFill();
            
            addChild( _up );
            addChild( _down );
            
            _up.x = _down.x + _down.width + 4;
            
            _up.addEventListener( MouseEvent.CLICK, click_up );
            _down.addEventListener( MouseEvent.CLICK, click_down );
        }
        
        private function click_up( e:MouseEvent ):void {
            _model.add_one();
        }
        
        private function click_down( e:MouseEvent ):void {
            _model.subtract_one();
        }
    }
}

The code added above does the following.

It first defines two private variables _up and _down. These will hold a reference to the two Sprites I will use as buttons.

Next it creates the _up Sprite, then draws a small rectangle 22px by 22px inside _up. Then it creates the _down Sprite and draw another box. Then I added both boxes to the display list. Next I position _up 4 pixels to the right of _down.

Last I added an event listener to each _up and _down. These call the two handlers, click_up and click_down, which are defined below.

Notice the two handlers, click_up and click_down, each use the reference _model to call on the Model's public methods.


Putting all together
Now that we have the classes written how do you put it all together? In a nutshell, make an instance of Model, then make an instance of View and Controller passing your model instance along. Since View and Controller are both display Objects you'll need to add them to the display list and position them.

Try it for yourself. Make a new Flash file. Save it into the folder containing the Model.as, View.as and Controller.as files. Then create a new AS file, we'll use this as the Document class for the example, save the file as Main.as, it must go in the same folder as the Fla.

Next add the following code to Main.as.

package {
    import flash.display.*;
    import flash.events.*;
    
    public class Main extends MovieClip {
        public function Main() {
            var model:Model = new Model();
            
            var view:View = new View( model );
            var controller:Controller = new Controller( model );
            
            addChild( view );
            addChild( controller );
            
            view.x = 100;
            view.y = 100;
            controller.x = 100;
            controller.y = view.y + view.height + 4;
        }
    }
}

I colored the Model in red, the View in blue and the Controller in green.

Test the Movie and you should see two small black squares on the stage. Clicking one should make the View display the value stored in Model and increase the value by 1. Clicking the other should decrease the value stored in Model by 1 and cause the View to display the updated value.


How does it all work?
The Model is set up to dispatch change events whenever the data it stores changes. Model provides some methods to allow the data to be changed. In this case add_one and subtract_one add or subtract one and dispatch a change event.

The View is passed a reference to Model and registers to listener for change events. If something changes in the Model, View is notified and then gets the information it wants from Model using Model's get_data method.

The Controller is passed a reference to Model. Through this reference it calls Model's methods that change the data it stores. In this it's the add_one and subtract_one methods.

Why use this Design Pattern
Using the design pattern separates the basic elements that we are working with into distinct classes that each manage one aspect of the system. This provides several advantages.

It makes editing easier. Since functions of the system are contained in separate classes, making a change is easier since we can edit the class responsible for that system. Rather than untangling code mixed with other systems.

It makes expanding the system much easier. To add another controller or View element to the system becomes as easy as writing a new class. Each new View or Controller will follow the same arrangement also. They will receive a reference to Model. View's will also register for change events.

The Model can also be more easily expanded for the same reasons. 


MVC Gallery
The MVC pattern makes a great choice for a Flash image gallery. Imagine a gallery that displays a large image, a set of smaller thumbnail images, some buttons to advance to the next or previous image, and a text field to display a description of the image.

The MVC pattern might break these elements into classes.

  • Gallery - This class will act as the Model for our system. It will store a list of all of the images, their descriptions and the thumbnail image.
  • GalleryViewImage - This class will act as a View. It will load and display the large image.
  • GalleryViewDetails - This class will act as a View. It will display the text description for the current image.
  • GalleryNextPrev - This class will act as a Controller. It will generate two buttons. Click one button will advance to the next image, clicking the other go back to the previous image. 
  • GalleryViewIcons - This will act as both a View and a Controller. The class will display a list of thumbnail images. Clicking any of these images will display the large version of that image.

These are main classes use in our system. There will be a couple other classes used but these are the classes that relate to MVC pattern.

Using XML with the Gallery
The gallery will use XML to describe the url of the images, their descriptions and the urls to their thumbnail images. If you are not familiar with XML please see the chapter on XML.

XML makes a great system to hold and organize all of the information that describes the gallery. It also makes our gallery flexible, since the XML file can be easily updated to change the images displayed in the gallery. It makes the entire project flexible in that you can reuse the swf with a different set of images and a different XML file in another site with out having create a new project.

This project will make use the XMLLoader class to load XML. Please see the chapter on this class if you are familiar with it and need more info.

The Gallery XML
The XML file we'll use for this project will be fairly simple. We'll use <gallery> as the top level tag. Inside which will be a series of <image> tags. One for each image in the Gallery. For example:

<gallery>
<image></image>
<image></image>
...
</gallery>

We'll have as many <image> tags as there are images in our gallery.

Each <image> tag will hold tags that describe each image. For each image we'll need a URL to the image, a URL to the thumnail image, and a text description of the image. For these we'll use the following tags:

  • <url> - URL to the image
  • <icon> - URL to the thumbnail image
  • <desc> - Text Description of the image

The finished XML file might look something like this:

<gallery>
    <image>
        <url>images/IMG_0089.jpg</url>
        <icon>images/IMG_0089_icon.jpg</icon>
        <desc>A picture of the SF skyline.</desc>
    </image>
    <image>
        <url>images/IMG_0115.jpg</url>
        <icon>images/IMG_0115_icon.jpg</icon>
        <desc>Another picture</desc>
    </image>
    ...
</gallery>

You can repeat each <image> tag and it's nested tags once for each image in your gallery.


Loading Images
This project will use the ImageLoader Class to load both the large image and the thumbnail images. Be sure to read the chapter on these classes if you are not familiar with them.

By using a class to cover this functionality we save time. It makes our job easier and our projects better.


The Gallery class
The Gallery class will act as the Model for our system. It will store a list of the images, really it will store the URL to each image as a string, we'll rely on a View to actually load and display the image. Gallery will also store the description for each image and the URL to each thumbnail image.

The Gallery will need to provide public functions to accommodate it's views. Since the GalleryViewImage will display the current image, we'll include an index property that keeps track of the current image on display. This will also work with the GalleryViewDesc. The controller will set increment the index to display the next image. Or decrement the index to show the previous image.

The Gallery class also needs a method to provide a list of the URLs of the thumbnail images. This will be needed by the GalleryViewThumbnails class.

The Gallery class will extend EventDispatcher since will need to dispatch event messages. The Gallery will dispatch two types of events. It will the CHANGE event in the same way that the Simple MVC example used it. Since it will load the XML file it will also dispatch a COMPLETE event to notify us when the XML file has been loaded.

Here's the basic Gallery class:

package {
    import flash.events.*;
    import com.webdevils.net.XMLLoader;
    import com.webdevils.utils.BasicIterator;
    
    public class Gallery extends EventDispatcher {
        private var _gallery_xml:XMLList;
        private var _index:uint;
        
        public function Gallery( url:String ) {
            load( url );
        }
        
        // ******* Private Functions *******
        private function on_complete( e:Event ):void {
            _gallery_xml = new XML( e.target.data ).image;
            _index = 0;
            dispatchEvent( new Event( Event.COMPLETE ) );
            dispatchEvent( new Event( Event.CHANGE ) );
        }
        
        // ******* Public Functions ********
        public function load( url:String ):void {
            var xml:XMLLoader = new XMLLoader( url );
            xml.addEventListener( Event.COMPLETE, on_complete );
        }
        
        public function next():void {
            if ( _index < _gallery_xml.length() - 1 ) {
                _index ++;
            }
            dispatchEvent( new Event( Event.CHANGE ) );
        }
        
        public function prev():void {
            if ( _index > 0 ) {
                _index --;
            }
            dispatchEvent( new Event( Event.CHANGE ) );
        }
        
        public function hasNext():Boolean {
            return Boolean( _index < _gallery_xml.length() - 1 );
        }
        
        public function hasPrev():Boolean {
            return Boolean( _index > 0 );
        }
        
        public function iterate_icons():BasicIterator {
            var icons_array:Array = new Array();
            var it:XMLIterator = new XMLIterator( _gallery_xml );
            while( it.hasNext() ) {
                icons_array.push( it.next().icon.toString() );
            }
            return new BasicIterator( icons_array );
        }
        
        
        // Getter Setters
        public function get index():uint {
            return _index;
        }

        public function get length():uint {

            return _gallery_xml.length();
        }
        
        public function set index( n:uint ):void {
            _index = n;
            dispatchEvent( new Event( Event.CHANGE ) );
        }
        
        public function get image():String {
            return _gallery_xml[ _index ].url.toString();
        }
        
        public function get desc():String {
            return _gallery_xml[ _index ].desc.toString();
        }
        
    }
}


Gallery properties
The Gallery class has two private properties _gallery_xml and _index. The _gallery_xml property will hold an XML object that describes the gallery. The _index property holds the index of the current image on display in the Gallery.

Gallery methods
The Gallery class provides a few methods. They are all pretty short. Most of the methods are public and have as their goal providing information for the various Views and allowing the Controller to make changes to the Gallery.

The Constructor takes a single parameter, the URL to the gallery XML file to load. This is a String. The Constructor just passes this item on to the load method which actually starts the loading process.

public function Gallery( url:String ) {
    load( url );
}


The load method takes a single parameter, the URL of the file XML file to load. This method creates a new instance of the XMLLoader class and passes the url.

Then we add an EventListener to our XMLLoader instance. This listener listens for the COMPLETE event which is handled by the on_complete method.

Making this method public makes the class a little more flexible.

public function load( url:String ):void {
    var xml:XMLLoader = new XMLLoader( url );
    xml.addEventListener( Event.COMPLETE, on_complete );
}

The on_complete method is where store the XML file we just loaded and notify any listeners that we have completed the loading process. This method is private since it makes no sense for any other class to have access to it.

We'll also set _index to 0 here. After loading our XML file the Gallery should be viewing the first image.

We also dispatch a CHANGE event to any of our listeners. So all the listeners will update and draw themselves based on the new data loaded.

private function on_complete( e:Event ):void {
    _gallery_xml = new XML( e.target.data ).image;
    _index = 0;
    dispatchEvent( new Event( Event.COMPLETE ) );
    dispatchEvent( new Event( Event.CHANGE ) );
}


To enable the Next and Previous buttons the Gallery class provides the next and prev methods. These are very similar. They increment or decrement the _index by 1. They also check the current value of of _index to make sure that it doesn't get out of range. Last of all they dispatch a CHANGE event.

To make sure _index does not reference an index beyond the last image we check the length of the XMLList, _gallery_xml. Note the of the XMLList tells the number of items in the list, items in he list are indexed starting on 0. So we need to subtract 1 from length to get the number of the last index.

public function next():void {
    if ( _index < _gallery_xml.length() - 1 ) {
        _index ++;
    }
    dispatchEvent( new Event( Event.CHANGE ) );
}
        
public function prev():void {
    if ( _index > 0 ) {
        _index --;
    }
    dispatchEvent( new Event( Event.CHANGE ) );
}


We will want the next and previous buttons to know when there are images available. And, when there are no images available we'll want the next button to disable itself. The same goes for the previous button when we're on the first image.  For that we'll use the hasNext and hasPrev methods.

These two methods return a Boolean (true or false). The first, hasNext, checks that the _index is less than the length of the XMLList -1. If this is true, there is a next image to view.

The second method, hasPrev, checks that _index is greater than 0. If it is there is a previous image available. 

public function hasNext():Boolean {
    return Boolean( _index < _gallery_xml.length() - 1 );
}

public function hasPrev():Boolean {
    return Boolean( _index > 0 );
}


The iterate_icons method is used to list all of the URLs to the thumbnail images. This function makes use of the Iterator Patern be sure to read the section on Iterator.

The first step is to make an a new empty Array. Then create an XMLIterator to iterate through the _gallery_xml XMLList. We get the URLs of the thumbnails from the icon element and add them to the icons_array. Last, return an Iterator for the icon_array.

public function iterate_icons():BasicIterator {
    var icons_array:Array = new Array();
    var it:XMLIterator = new XMLIterator( _gallery_xml );
    while( it.hasNext() ) {
        icons_array.push( it.next().icon.toString() );
    }
    return new BasicIterator( icons_array );
}


The last four functions are getter setter functions, see the chapter on functions for more info on these. These allows us us to get and set properties of the Gallery class. This is a great example of getters and setters at work.

The set index function allows us to set the value of _index. In the same way that we would set the value of any property for any other object. Why using a setter function is so important here is that changing the value of _index means that the View and Controller need to be notified. If we had used a public property, you could change the value from outside of the class and Gallery would have no idea that the value you had changed. using a setter here allows our class to run the function when the value changes.

Notice the setter function dispatches a CHANGE event after the value of _index is set to a new value. I included the getter for index since a View or Controller for Gallery might need to know what the current index was.

public function get index():uint {
    return _index;
}

public function set index( n:uint ):void {
    _index = n;
    dispatchEvent( new Event( Event.CHANGE ) );
}

Notice that I used the name index for the name of each function. Accessing these two getter and setter functions from outside the class we'll use the name index as the property name. For example:

_gallery.index = 5; // Sets _index

or

trace( _gallery.index ); // Gets _index


Our main view will need to know what the URL for image at the current index is. For this I used a simple getter function called image. This makes it easy for a View to get the URL from the image property.

public function get image():String {
    return _gallery_xml[ _index ].url.toString();
}

For example any class with a reference to a Gallery instance could get the image at the current index with:

_gallery.index


The last getter returns the description for the current image. Again I used a simple getter named desc.

public function get desc():String {
    return _gallery_xml[ _index ].desc.toString();
}

Any View that needs the description for the current image can use the following:

_gallery.desc

A class might need to know how many images are in the Gallery. We can use the length() method of the XMLList class to find out how many images nodes there are.
 
public function get length():uint {
    return _gallery_xml.length();
}





Testing the Gallery class
To get a better understanding of the Gallery class test it out. Taking a good look at the Gallery itself is a good idea and will give you a better idea of it's role in the MVC pattern.

For this test we'll use the trace statement. If you're not familiar with this or need more information see the chapter on trace.

Create a new Fla file in the same folder as the Gallery.as file. In this case we'll add the script to the timeline on frame 1. This will be convenient for the test.

Make a new instance of the Gallery class:

var gallery:Gallery = new Gallery( "slideshow.xml" );

Next, set add a COMPLETE event to the gallery. The gallery needs to load it's XML before it has any data to work with. Add the following:

gallery.addEventListener( Event.COMPLETE, on_complete );
function on_complete( e:Event ):void {
    // test code here
}

From here we can test all of the Gallery classes methods and properties. Each of the followoing lines will test a property or method of the Gallery class. each line needs to be added to the on_complete handler.

Find the current index (add the following line to the on_complete handler):

trace( "The current index is:" + gallery.index );

Test your Movie. The Output window should open and show:

The current index is:0

It shows 0 because the first index, that is the position of the first image is 0.

Try another. Test the length.

trace( "Length:" + gallery.length );

Next get the URL to the current image:

trace( gallery.image );

Now advance to the next image and then test the image property again:

gallery.next();
trace( gallery.image );

You can see the Gallery contains and organizes all of the information/data needed to run the gallery. It doesn't display images or make things happen on it's own. Instead it makes these features available via it's properties and methods. This is the goal of the Model in MVC.






GalleryViewImage
The GalleryViewImage class will be used to display the current image. This is the image set by _index within the Gallery class. The gallery class will supply the URL to the GalleryViewImage will load and display the Image.

To make things easy for ourselves we'll use an instance of the ImageLoader class. If you are not familiar with this class be sure to read it's chapter. Basically this class encapsulates the Loader class and adds a few features. You could build your own View around the Loader class or another class instead of ImageLoader also.

This class extends Sprite so we can add it to the stage. Since it is a View, it takes a Gallery instance as an argument in it's constructor and registers with the Gallery instance for CHANGE events.

I've also added arguments for width and height. Since the ImageLoader class requires these, I can easily pass them along when making an instance of GalleryViewImage. This will allow us to easily set up the class to work with different sized images when using the class with different projects.

The only other function here is on_change. In this View on_change gets the image value, vie Gallery's image getter. This returns the URL to current, so we pass it along to out ImageLoader instance's load_image method, and ImageLoader loads the new image.

package {
    import flash.display.*;
    import flash.events.*;
    import com.webdevils.display.ImageLoader;
    
    public class GalleryViewImage extends Sprite {
        private var _gallery:Gallery;
        private var _image:ImageLoader;
        
        public function GalleryViewImage( gallery:Gallery, w:Number, h:Number ) {
            _gallery = gallery;
            _gallery.addEventListener( Event.CHANGE, on_change );
            _image = new ImageLoader( "", w, h );
            addChild( _image );
        }
        
        private function on_change( e:Event ):void {
            _image.load_image( _gallery.image );
        }
    }
}


GalleryViewDetails
This is another View that displays the description for the current image. It is very similar to the GalleryViewImage class. With the difference being it contains a TextField in place of the ImageLoader.

Again this class follows the pattern for Views. It takes a reference to the Model, in our case a Gallery instance in the constructor. It saves a reference to the Model, and registers with the Model for CHANGE events.

The on_change handler gets the description for the current image through Gallery's desc getter.

package {
    import flash.display.*;
    import flash.events.*;
    import flash.text.*;
    
    public class GalleryViewDetails extends Sprite {
        private var _gallery:Gallery;
        private var _txt:TextField;
        
        public function GalleryViewDetails( gallery:Gallery,w:Number,h:Number ) {
            _gallery = gallery;
            _gallery.addEventListener( Event.CHANGE, on_change );
            
            var fmt:TextFormat = new TextFormat();
            fmt.font = "Verdana";
            fmt.size = 16;
            
            _txt = new TextField();
            _txt.defaultTextFormat = fmt;
            addChild( _txt );
            _txt.width = w;
            _txt.height = h;
        }
        
        private function on_change( e:Event ):void {
            _txt.text = _gallery.desc;
        }
    }
}

GalleryPrevNext
This class acts as a Controller. It displays two buttons. In this example I have created the buttons via AS to keep the example contained in the text of the class. You could easily have used MoveClips from your library instead.

The two buttons when click call on the next and prev methods of the Gallery class. Which either advances Gallery to the next image sends it to the previous image. Gallery then, of course, in good MVC style, dispatches a CHANGE event, to notify it's Views, which then update their display.

This class also registers for CHANGE events. The on_change handler in GalleryPrevNext, is used to enable and disable the next button when there is not next image, or disable the previous button when there is not previous image. In this way this class acts as a View also.

package {
    import flash.display.*;
    import flash.events.*;
    
    public class GalleryPrevNext extends Sprite {
        private var _gallery:Gallery;
        private var _next:Sprite;
        private var _prev:Sprite;
        
        public function GalleryPrevNext( gallery:Gallery ) {
            _gallery = gallery;
            _gallery.addEventListener( Event.CHANGE, on_change );
            
            make_buttons();
        }
        
        private function make_buttons():void {
            _next = new Sprite();
            _next.graphics.beginFill( 0x999999 );
            _next.graphics.drawRect( 0, 0, 32, 32 );
            _next.graphics.endFill();
            addChild( _next );
            
            _prev = new Sprite();
            _prev.graphics.beginFill( 0x999999 );
            _prev.graphics.drawRect( 0, 0, 32, 32 );
            _prev.graphics.endFill();
            addChild( _prev );
            
            _next.x = _prev.width + 6;
            
            _next.addEventListener( MouseEvent.CLICK, click_next );
            _prev.addEventListener( MouseEvent.CLICK, click_prev );
        }
        
        private function click_next( e:MouseEvent ):void {
            _gallery.next();
        }
        
        private function click_prev( e:MouseEvent ):void {
            _gallery.prev();
        }
        
        private function on_change( e:Event ):void {
            if ( _gallery.hasNext() ) {
                _next.alpha = 1;
                _next.mouseEnabled = true;
            } else {
                _next.alpha = .5;
                _next.mouseEnabled = false;
            }
            
            if ( _gallery.hasPrev() ) {
                _prev.alpha = 1;
                _prev.mouseEnabled = true;
            } else {
                _prev.alpha = .5;
                _prev.mouseEnabled = false;
            }
        }
    }
}


GalleryViewIcons
The GalleryViewIcons Class is probably the most difficult class of the bunch. This class needs to display the icons and allow a click to load the image associated with the icon.

Since there may be more icons than might fit in the area you've designated for the icons, GalleryViewIcons will need to scroll or paginate the icons.

There may be even more features associated with this class. The GalleryViewIcons class could be a Model View Controller system all to itself. In the example here we won't go that far. A class this complex definitely needs to be broken down into several smaller classes.

The icons will need to load the icon image, display an over and selected state and remember the index of the image they are associated with.

The icons will need a container. The container will need to arrange and display the icons. It will need to define an area where they appear and mask off this area. The container may also need to move or paginate the icons to show icons that may not be visible under the mask.

There may be other or alternative features needed or alternate approaches to what I have described here. We'll just work with this feature set for the examples.

The GalleryIcon class
This class will load the icon image and act as  a button. As a button the icon will need to show an up, over, down and disabled face.

Several approaches could be taken for this class. The example will create use a border for the selected state and modify the color of the image for the rollover and down states.

Create a new class file. Save it as GalleryIcon




Create a slide show presentation using Gallery
This Gallery makes a great base for a lot of applications. Using just the GalleryPrevNext class as the Controller you could create a linear slideshow/presentation. With a new Controller, that used the keyboard to display the next and previous image the application becomes very practical to use.