PDA

View Full Version : MVC and objects already on the stage


midimid
05-29-2008, 06:35 PM
So I'm finally really digging into design patterns with AS3 and I'm finally getting the hang of it. I'm currently floating through Adobe's "Advanced ActionScript 3.0 with Design Patterns" by Lott and Patterson.

For the MVC pattern, where exactly does an object fit in that has already been placed on the stage?

The problem comes up because an object on the stage at compile time is immediately instantiated without any real control as to "how" it is instantiated (afaik). The above book's clock example shows adding objects dynamically through an Abstract view, but that view requires arguments, and I don't see how you can pass those arguments at compile time.

Just a bit confused how to combine this together. Check out the clock example here:
http://rightactionscript.com/aas3wdp/

midimid
05-29-2008, 11:26 PM
Anyone?

i.e. take the Clock example linked above. Lets say I wanted to use the same pattern, but add two new things:

1) A New Button - drawn as a movieclip already on the stage or in the library
2) A moveiclip containg a text box of class AbstractClockView - again, already on the stage or in the library.

Then create this behavior (which I'm assuming would mainly bei n the controller):
- when the button is clicked, show some the time data variable in the texbox as a string.


I'm pulling my hair out trying to get something simple like this working. No one seems to know anything about the stage except for the main application itself. Why aren't there any good examples out there about something so simple as using AS3 design patterns WITH premade moveiclips - either drawn on a Flash stage or just in the library?

Help! Really need to get over this learning curve...

hbd
06-06-2008, 06:11 AM
Instead of using constructor, you can pass paremeters like this.

Abstract Class
public funcion initialize( data ){...}

Concrete Classes
public override funcion initialize( data ):void{
super.initialize( data );
...blah blah
}

Controller
instance.initialize( data );

Mazoonist
06-15-2008, 06:30 AM
I'm working through the same book, midimid. So I understand where you're coming from; I'm trying to absorb some of these design patterns myself. I was able to alter the class files a bit and make it use stage instances instead, and here's what I did:

1. Working in the fla file, create a new MovieClip by choosing the Insert menu, then "New Symbol." Choose MovieClip type and name it Clock. Don't worry about the linkage just yet. In the edit mode for the clip, draw out three dynamic text boxes. Give them instance names of "_hours", "_minutes", and "_seconds." I found I might as well give them instance names that match the ones that the class makes dynamically--that way I won't have to change as many references in the class file. Next, draw a rectangle (to the right of the text boxes), select it, and convert it to a symbol. I chose to use the MovieClip type, and named it ToggleButton. But I gave the instance on the stage an instance name of "_toggleView." Once again, I figured if I go with the same name the class uses I won't have to make as many changes in the class. Next, right click the ToggleButton library symbol and choose Linkage. Check off "Export for Actionscript" and for a base class, change "flash.display.MovieClip" to "flash.display.Sprite" instead. Go back to the main timeline of scene 1. Drag an instance of Clock out to the stage and give it an instance name of "clock." Finally, we need to set the linkage for the Clock library symbol. What I did is went to Clock.as, and copied the package line (except for the word "package") so that I got "com.peachpit.aas3wdp.mvcexample.controllers"
Now go back to the fla file, right click the Clock symbol, Check off "Export for actionscript," and for the class, paste in the previously copied path, and add ".Clock" to the end of it. This will set up linkage so that the library symbol IS the class and vice versa. Once again, change the base class to "flash.display.Sprite." I just changed the base class to Sprite so that I wouldn't have to import MovieClip in the Clock.as class file, but you can really do either one. If you leave it as a MovieClip, then in the class file, you'll just have to import MovieClip too or you'll get an error message.

2. Next, I altered the Clock.as file as follows: Comment out all the code that has to do with the creation of the button, and the creation of the TextFields. Also the code that declares all those things. Leave the code that adds the event listener to the button. Since I used the same instance name, that will still work, but now it will refer to my stage instance instead.

3. Finally, I altered the ClockTest.as file as follows: I just commented out the code that creates and adds an instance of Clock, specifically these lines:
var clock:Clock = new Clock()
addChild(clock)
But you'll see I kept the line in between that says:
clock.data = clockData;
Once again, though, now "clock" refers to my stage instance instead of a dynamically generated one.

I'm uploading the fla file, and here are the altered AS files:
Clock.as:
package com.peachpit.aas3wdp.mvcexample.controllers {
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.events.FocusEvent;
import com.peachpit.aas3wdp.mvcexample.data.ClockData;
import com.peachpit.aas3wdp.mvcexample.clock.AbstractCloc kView;
//import com.peachpit.aas3wdp.controls.BasicButton;
import flash.events.MouseEvent;
import flash.events.Event;
import com.peachpit.aas3wdp.mvcexample.data.Time;
public class Clock extends Sprite {
//private var _hours:TextField;
//private var _minutes:TextField;
//private var _seconds:TextField;
private var _clockData:ClockData;
private var _viewIndex:int;
private var _views:Array;
//private var _toggleView:BasicButton;
public function set data(value:ClockData):void {
_clockData = value;
_clockData.addEventListener(Event.CHANGE, onModelUpdate);
onModelUpdate();
}
public function Clock() {
_views = new Array();
//_hours = createField();
//_minutes = createField();
//_seconds = createField();
//_minutes.x = 45;
//_seconds.x = 90;
//_toggleView = new BasicButton("Toggle View");
_toggleView.addEventListener(MouseEvent.CLICK, toggleView);
//addChild(_toggleView);
//_toggleView.x = 135;
}

public function addView(view:AbstractClockView):void {
_views.push(view);
if(_views.length == 1) {
addChild(view);
_viewIndex = 0;
}
view.y = 40 - view.getBounds(view).top;
view.x = -view.getBounds(view).left;
}
/*private function createField():TextField {
var field:TextField = new TextField();
field.width = 40;
field.height = 22;
field.border = true;
field.background = true;
field.restrict = "0-9";
field.type = TextFieldType.INPUT;
field.addEventListener(FocusEvent.FOCUS_OUT, onValueChange);
addChild(field);
return field;
}*/
private function onValueChange(event:FocusEvent):void {
if(event.target.length < 1) {
event.target.text = 0;
}
var time:Time = new Time(uint(_hours.text), uint(_minutes.text), uint(_seconds.text));
_clockData.time = time;
}
private function toggleView(event:MouseEvent):void {
removeChild(_views[_viewIndex]);
_viewIndex++;
if(_viewIndex >= _views.length) {
_viewIndex = 0;
}
addChild(_views[_viewIndex]);
}
private function onModelUpdate(event:Event = null):void {
if(stage != null) {
if(stage.focus != _hours) {
_hours.text = _clockData.time.hour.toString();
}
if(stage.focus != _minutes) {
_minutes.text = _clockData.time.minute.toString();
}
if(stage.focus != _seconds) {
_seconds.text = _clockData.time.second.toString();
}
}
}

}
}
ClockTest.as:
package {

import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import com.peachpit.aas3wdp.mvcexample.data.ClockData;
import com.peachpit.aas3wdp.mvcexample.clock.AbstractCloc kView;
import com.peachpit.aas3wdp.mvcexample.clock.AnalogClock;
import com.peachpit.aas3wdp.mvcexample.clock.DigitalClock ;
import com.peachpit.aas3wdp.mvcexample.controllers.Clock;

public class ClockTest extends Sprite {

private var _clockData:ClockData;

public function ClockTest() {

stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;

_clockData = new ClockData();
_clockData.realTime = true;

//var clock:Clock = new Clock();
clock.data = _clockData;
//addChild(clock);

var view:AbstractClockView = new DigitalClock(_clockData);
clock.addView(view);

view = new AnalogClock(_clockData);
clock.addView(view);

}

}
}
Hope this helps, and I agree that there's kind of a shortage of good information on these subjects, as well as a gap between designing and developing in Flash. On the one hand you have the timeline and the designing environment, but on the other hand you're made to feel like you ought to have an empty stage and timeline and create everything with code instead. There's got to be a happy medium here somewhere, eh?

midimid
06-15-2008, 11:30 AM
Thanks for the replies. I haven't dug through your attached code yet, but thought I'd pass a quick reply from the past few weeks.

I found the clock example to be cumbersome in learning this methodolgy. Instead, I moved to OReilly's AS3 Design Patterns book. Its MVC chapter is excellent. Going through THAT code, I haven finally been able to go back to the original book I picked up(IMHO, the best - Head First's Design Patterns - but its in Java) and actually understand what I'm reading.

I was still a bit perplexed about abstract classes and how they play in with movieclips ON the stage, so I just took them out. Working from there and a different thread on kirupa, I ended up making a composite/component pattern by "setting" the model to movieclips on the stage outside of the constructor. It was the ONLY solution. Similar to what fbd has mentioned.

What Adobe needs to do is give the user more control over the intitialization for MovieClips on the stage. I know the above is "enough" but for the average design pattern learner, its extremely unclear.


In the end, I think the best advice I read was "Design Patterns are meant to be GUIDlines, not rules to live by." When first starting out with this, I felt I had to create my real-world examples based strictly on the rules given, but its really not always needed. It seems to me that the expert at designing with design patterns is someone who can make it use the rules' potential but not be bound by them.

creynders
06-15-2008, 04:48 PM
Another approach would be to use a movieclip instance on the stage as a property of a view class, instead of writing code for it directly. That's IMO the easiest and most clean solution.