Ultrashock Forums > Flash > ActionScript > OOP
App: MVC Gallery
Member Blogs
 
Post Reply | View first unread | Rating: Thread Rating: 6 votes, 4.50 average. Search this Thread | Thread Tools | Display Modes
1|2|3|>|>> Page 1 of 6

#1
Bookmark and Share!
App: MVC Gallery
Old 2005-11-28 Last edited by Codemonkey : 2007-10-10 at 00:53.

09 Oct. 2007 - Added references other people's related work
- Nutrox' Google public project Neondust base Framework
- wraevn's AS3 version of this web gallery

13 May. 2007 - Added references for further reasearch
-------
MVC Gallery in-depth

So after a night of coding Saturday I finished the mvc gallery project. After some more time I got everything commented as well. It got much more than I intended. I had something like Nutrox made in mind, to just demonstrate (and get myself familiar with) the mvc pattern, but I couldn't let it go . Anyway, if you would like to know what this gallery is all about read on, otherwise just download the source and see if you can use it. It’s not really a tutorial and it may or may not be very dry to plow through. I don't tell very well, but let’s just get down to it shall we?

demo
MVC Gallery source
image folder
note: I used Nutrox' html file from his tutorial (hope you don't mind )

First things first, what are those patterns and why we need them. If you are familiar with the principles of these design patterns, you might want to skip ahead to the second post. How to make the gallery do a slide show is in the third post.

Introduction Singleton pattern:
This is the smallest and easiest pattern I know. It involves only one class, and has little to no implementation. The point is to make a class so, that you can make only one instance of it. This is done using a static class method that stores an instance variable. Only if that instance variable is null or undefined, it will make a new instance of this class. More information here

Check out these discussions about singletons on Ultrashock as well:
Singleton pattern and globals
MVC with screen manager (singleton suggested to manage screen instances with)

Introduction Observer pattern:
The observer pattern is pretty simple. Its objective is to make sure everybody listening at a single object knows when that single objects has changed or is doing something they should know about. The observer pattern defines a few specified methods for an Observable and one method for the Observer. The observable object needs to do some registering and stuff to get all listeners together and the observers just need to implement a method called update, which is called by the observable. Check this link for some more information.

Introduction to MVC:
MVC isn’t really hard to understand, but the possible combinations can cloud things up. The basic principle is: the model is the data organizer and container. The view uses this data to create a (graphical) representation. If the view wants to changes anything to the model, like when you hit a button or something, the view has a controller in its arsenal to make it happen. Everything to preserve the distance between the model and the view. Even so much, the model prefers to send through data using a single info object and the view prefers to get it that way (otherwise the view would have to ask the model for information).

So how is the communication done between the model and the view? Through the observer pattern. It’s perfect, the model can be an observable, and the views are observers and so they can receive updates from the model. The observer pattern is perfect for this, because this is a relatively small project. A webgallary is nothing compared to an enterprise big company project. If it were such a project, we would need something more robust than observer, say an event delegation model.

For a very good walkthrough, check out Moock’s piece, most of what I know of the mvc came from there anyway.

For a very in-depth look at MVC, check out this site:
http://www.phpwact.org/pattern/model_view_controller

Why these patterns, you can do it without them!
Well… that’s true. But the bigger your project gets the more code and like you saw in my first attempt on this thread (not the very first though), you can see code is already clouding up on several layers. There is no order, no obvious ‘flow’, and everything can touch everything and so you are working one of those huge knots, like those you get your headphones in, except bigger. Sipher asked me if it was possible to add in sliding. Well, if I did it like before, then I would have to say I don’t know… probably, and not easily. I would have to look at the code to see ‘how I did it again’, but with this mvc version it is really, really simple. I’ll show you how when I explained how the gallery works.
XML is the glue of the future.
"Alkland's in Jeamland," I said. "Do you know what happened? I fell awake."
postbit arrow 218 comments | 10188 views postbit arrow Reply: with Quote   
Codemonkey
Super Moderator
Codemonkey is offline Super Moderator
seperator
Posts: 4,996
2001-04-05
Age: 24
Codemonkey lives in Netherlands
Codemonkey has 5 blog entries5
Codemonkey's Avatar
seperator

Ultrashock Member Comments:
Codemonkey's Avatar Codemonkey Codemonkey is offline Super Moderator Codemonkey lives in Netherlands 5 Blog Entries 2005-11-28 #2 Old  
Last edited by Codemonkey : 2007-03-01 at 13:58.
So ehh, all that stuff and still nothing about that gallery:
Fine, I’ll treat you on a diagram for your sore eyes then.



I took over Moock’s style for these diagrams, since I already had so much use from his book Essential Actionscript 2. You can see at the colors what pattern they belong to and how the gallery classes consists of these.
The two interfaces Observer and View define a set of functions for their patterns and AbstractView implements all of these to define the basic functionality for a view of the mvc pattern. This is to observe an observable object, the model, and to be able to communicate back to the model either directly to retrieve data or more commonly via the controller to request changes. GalleryView is such a view as is ControlsView.

GalleryView creates the interface of the gallery and ControlsView is part of that (with the previous and next buttons). First I had GalleryView as the only view, but then it was hard to communicate with the model, which only the GalleryView could do. So I made the controls also a view.

Then there is the Controller, who can directly talk to the model and optionally make changes. The GalleryController receives requests from both views and makes sure the model reacts accordingly. The buttons ask the model to activate the previous or next image, the thumbnails ask for a specific image and the GalleryView requests that the model loads the next image from xml after the thumbnails bar on the left has preloaded and shown the last thumbnail.

And then there is the observable, our model, which contains all the gallery data (title, image list, current activated image and percentage of total images loaded from xml).

Last is the GalleryUpdate class. This class contains all the data I just mentioned and the nature of the update. Or rather the state the model is in (starting up, loading images, viewing images etc.).

Here’s an image that shows the various classes.



These are all the custom classes in the gallery project. All the white classes are actually assets in the library with a class attached to them. These have the benefit to already have graphical stuff done and can easily be changed to alter the way the gallery looks. They actually have more objects, but they are all MovieClips which I haven’t listed here, but they are part of the white classes.

The GalleryView has a ViewArea, the main window where the image is viewed. Also has the NavBar, which contains the ThumbImages. GalleryView also has the ControlsView, which has the button previous and next. The NavBar also has the slider.
ViewArea and ThumbImage extend PreloadImage because they both have load an image from an url and both need to preload them before showing. Perhaps a poor choice of name, but it does the job. PreloadImage makes use of our custom preloader class, which is actually just a listener for a MovieClipLoader, as the cliploader calls methods on its listeners like onGetProgress().

So that’s it. I’m not going into the classes, that would be too much work, but I have commented them enough so you should be able to understand it. Look back at these diagrams to see how the classes relate.
Reply With Quote  
Codemonkey's Avatar Codemonkey Codemonkey is offline Super Moderator Codemonkey lives in Netherlands 5 Blog Entries 2005-11-28 #3 Old  
Last edited by Codemonkey : 2006-01-22 at 14:16.
Adding slideshow functionality:
Ok, when I said that this is easy to do, I didn’t lie. All you need to do is add a button to the Controls asset, and when that button is hit, it sends a request to the model telling it to slideshow the images. The model then updates the active image at an interval and sends an update to all the views each time.

Step by step:

1. Go to the GalleryModel class and add these two methods

ActionScript Code:
  1. private var id:Number = -1; // I did the assignment in the constructor
  2.  
  3. // switches the slideshow mode
  4.     public function switchSlideshow() {
  5.         if (id == -1) {
  6.             id = setInterval(this, "nextSlide", 5000);
  7.         } else {
  8.             clearInterval(id);
  9.             id = -1;
  10.         }
  11.     }
  12.    
  13.     // slide to next image, called on an interval if in slideshow mode
  14.     private function nextSlide() {
  15.         cycleImage(1);
  16.     }
2. Go to the GalleryController class and add this method

ActionScript Code:
  1. // makes the model show (activate) the next image in the imagelist
  2.     public function switchSlideshow() {
  3.         GalleryModel(getModel()).switchSlideshow();
  4.     }
3. Open up the controls mc asset in the library and add a button. Give the button the name “btn_slideshow”. I made it between the buttons previous and next.

4. Open the class Controls, and add the public variable btn_slideshow:MovieClip. Now we can use the button inside the class.

5. Open up the class ControlsView and add this method

ActionScript Code:
  1. private function switchSlideshow() {
  2.         GalleryController(getController()).switchSlideshow();
  3.     }
and in the constructor, add this line

ActionScript Code:
  1. controls.btn_slideshow.onRelease = Delegate.create(this, switchSlideshow);
And you’re done! You could make the slideshow show random images by using this instead.

ActionScript Code:
  1. // slide to random image, called on an interval if in slideshow mode
  2.     private function nextSlide() {
  3.         cycleImage(random(images.length));
  4.     }
And all the views controls and stuff update correctly. See the thumbs highlighting with each image?
Reply With Quote  
Nutrox's Avatar Nutrox Nutrox is offline Nutrox lives in United Kingdom 1 Blog Entries 13 Creative Assets 2005-11-28 #4 Old  
Wheyhey! Very nice, Codemonkey.

I haven't read through it all in detail yet (I'm pulling an all-nighter so I'll read it all later on) but it's all looking good.

Let the battle of the Galleries begin.

A quick question for you...

As far as the MVC pattern goes, am I right in thinking that the Model only sends data to the View, and the Controller only sends data to the Model?
Reply With Quote  
Codemonkey's Avatar Codemonkey Codemonkey is offline Super Moderator Codemonkey lives in Netherlands 5 Blog Entries 2005-11-28 #5 Old  
Originally posted by Nutrox
Wheyhey! Very nice, Codemonkey.

I haven't read through it all in detail yet (I'm pulling an all-nighter so I'll read it all later on) but it's all looking good.

Let the battle of the Galleries begin.

A quick question for you...

As far as the MVC pattern goes, am I right in thinking that the Model only sends data to the View, and the Controller only sends data to the Model?
In my implementation yes. The model sends data to the view using an info object, and the controller pulls the strings in the model on requests by views. The only other way would be if the views used getter methods in the model instead of using the info object.

Thanks
Reply With Quote  
sentinels sentinels is offline sentinels lives in United States 1 Blog Entries 2005-11-28 #6 Old  
very nice. i shall have to play around with this one a little later.
Reply With Quote  
Renjamin's Avatar Renjamin Renjamin is offline Moderator Renjamin lives in Canada 1 Blog Entries 2005-11-28 #7 Old  
Wonderful, Codemonkey.

Very nice.

Thank you!
Reply With Quote  
Nutrox's Avatar Nutrox Nutrox is offline Nutrox lives in United Kingdom 1 Blog Entries 13 Creative Assets 2005-11-29 #8 Old  
Another question for the Codemonkey.

Which class in the MVC pattern would handle the re-positioning of movie clips when the Stage was resized ( Stage.onResize ) ?

I imagine it's the View class, but is it viable for something outside of the MVC pattern to deal with Stage resizes?
Reply With Quote  
Codemonkey's Avatar Codemonkey Codemonkey is offline Super Moderator Codemonkey lives in Netherlands 5 Blog Entries 2005-11-29 #9 Old  
Yeah, I put it in the GalleryView (since that class is responsible of creating the interface). I could've included it in the function setupStage in the Gallery class, that's is the jumpstart class for the application.

But wherever it is, it has to be able to get through to the gallery view, to be able to call its realignmethods.

Btw, did you hit the keyboard with your head yet?
Reply With Quote  
Mike's Avatar Mike Mike is offline Moderator Mike lives in United Kingdom 2005-11-29 #10 Old  
Nice example monkey, I'm sure plenty of members will find it very helpful

In regards to the stage resizing, would it not be the case that a controller would be responsible for reacting to a stage resize event and calling an appropriate function of a custom stage object in the model to set it's new state.

Using your chosen implementation of the MVC pattern, Views can then register with this custom stage object and position themselves according to the info object (data transfer object) sent to them.
Reply With Quote  
Codemonkey's Avatar Codemonkey Codemonkey is offline Super Moderator Codemonkey lives in Netherlands 5 Blog Entries 2005-11-29 #11 Old  
If the stageresize had an impact on the actual data inside the model, I would say yes, the controller should update the model (or its stageobject) and then the model can update the views. But, since the stageresize is an aesthetic change only (not a change to match the model's data), the controller is allowed to update the view directly.

As you said though, the controller should probably be watching the stage for resize events, not the view.
Reply With Quote  
Nutrox's Avatar Nutrox Nutrox is offline Nutrox lives in United Kingdom 1 Blog Entries 13 Creative Assets 2005-11-29 #12 Old  
Originally posted by Codemonkey
...
Btw, did you hit the keyboard with your head yet?
Hehe... nope, not yet. I've done that thing where you stare at the screen for about 10 minutes in a mind-numbed state though.

You've actually got me interested in this whole MVC thing so I'm trying to structure something similar at the moment, but I'm including a class that handles audio as well ( Model, Display, Controller, Audio ). The Audio class isn't part of the "chain" though really, it's just connected to the Model class ( Model >> Audio | Model << Audio ).

I might also use a Global class that contains static pointers to the Model, Display, Controller, and Audio classes... and then simply import Global when one class needs to talk to another. I'll see how it goes though.
Reply With Quote  
Mike's Avatar Mike Mike is offline Moderator Mike lives in United Kingdom 2005-11-29 #13 Old  
Originally posted by Codemonkey
If the stageresize had an impact on the actual data inside the model, I would say yes, the controller should update the model (or its stageobject) and then the model can update the views. But, since the stageresize is an aesthetic change only (not a change to match the model's data), the controller is allowed to update the view directly.

As you said though, the controller should probably be watching the stage for resize events, not the view.
I see where you're coming from. Let me give some reasoning behind what I said.

I believe the controller should only directly update the view if there is no change to the related model's state (data), say reordering your images into alphabetical order for example.

I would say the Stage itself should be represented in the model as it has a state (alignment..) and these can be changed. As such this should not be done directly by the controller.
Reply With Quote  
imreimi's Avatar imreimi imreimi is offline imreimi lives in Canada 2005-11-29 #14 Old  
WOW. Nice. You guys are awesome. For me it is a HUGE HELP!

Hats down to you!!!!!!!

Imre
Reply With Quote  
Codemonkey's Avatar Codemonkey Codemonkey is offline Super Moderator Codemonkey lives in Netherlands 5 Blog Entries 2005-11-29 #15 Old  
Originally posted by BadSanta
I would say the Stage itself should be represented in the model as it has a state (alignment..) and these can be changed. As such this should not be done directly by the controller.
I see your point. Then the real question is: is the stage size 'state' part of the gallery data, or part of the interface that represents it?

Why do you feel the stagesize part of the galleries intrinsic properties if not of the interface?
Reply With Quote  
Mike's Avatar Mike Mike is offline Moderator Mike lives in United Kingdom 2005-11-29 #16 Old  
Ah ok, I think I get what you're saying (when you say interface I always think code ).

Well in this setup, your stage happens to only hold one view (GalleryView). Say the stage held 2 or more views at one time, then which one would have the stage size as their properties? Both, could be one answer but that's not very scalable.

My current line of thought would be to have a singleton, say StageModel, that views can subscribe to (along with other views) through their controller.

Oh that's another thing, it's perfectly valid for a view to subscribe to more than one model at a time. You would have to refactor your code slightly to allow this.

I would also be tempted to put stage resize listener directly into this StageModel as the width and height properties are read only and could not be set through a controller anyway, only alignment etc. can... but that's probably not the most "correct" thing to do for reasons stated previously (a controller should handle input events, but in this case the event has already update the stage x/y props, so what else would the controller need to do to the StageModel? Hmm but then again perhaps you would want the controller to perform some other custom action after a stage resize.. yeh I take it back in the controller is better! ).
Reply With Quote  
Nutrox's Avatar Nutrox Nutrox is offline Nutrox lives in United Kingdom 1 Blog Entries 13 Creative Assets 2005-11-29 #17 Old  
I've decided to put the Stage.onResize related stuff into the Controller.

The reason is that the user can click on a button to adjust the size of the GUI manually, and the Controller would need to catch that request and update the Model.

It makes more sense to me to have the Stage.onResize event call the Controller in the same way the View does when the user manually resizes the GUI, because both events are the same as far as the Controller and Model is concerned, and both events have exactly the same result ( the Model and View are updated ).
Reply With Quote  
Chaosfact's Avatar Chaosfact Chaosfact is offline Chaosfact lives in United States 2005-11-29 #18 Old  
I wish one day I could understand how the hell you did that.