The first chapter's about MVC pattern...
The book uses an example about CLOCK
I've code a version without MVC pattern for comparision:(2F show the MVC...)
=================================================
=================================================
the simplest version is:
1.. draw 3 Dynamic TextField whose instance's name's tf_hours,tf_minutes and tf_secondes
2.. frame 1 actionScript:
CODE:
function runClock(){
var d:Date=new Date();
tf_hours.text=d.getHours().toString();
tf_minutes.text=d.getMinutes().toString();
tf_seconds.text=d.getSeconds().toString();
}
3.. ctrl+ enter DONE....
==================================================
the version with document class (can be use in FLEX also)
import flash.display.Sprite;
import flash.text.TextField;
import flash.utils.setInterval;
public class SimpleClock extends Sprite {
/**
* SimpleClock类,MVC不分开
* 用法:
* 设一个AS3.0Fla 文件的DOcumentClass为 SimpleClock
* (如果fla与SimpleClock.as不在同一路径,要先设置类路径)
*/
// "View"
private var tf_hours:TextField;
private var tf_minutes:TextField;
private var tf_seconds:TextField;
public function SimpleClock() {
//
// 构造函数
// As3.0的Document Class的构造函数
// 相当于 JAVA 里的 public static main()入口函数
//
init();
/**
此处建议是用Timer类(与JAVA类似),
为求简单,(setInterval与javascript里的用法一样)
这里暂时用旧的函数方法。
Flash自带help里的说明:
Instead of using the setInterval() method,
consider creating a Timer object,
with the specified interval,
using 0 as the repeatCount parameter
(which sets the timer to repeat indefinitely).
*/
setInterval(runing,1000);
}
private function init() {
/**
* 界面初始化,
* 没有用类的最简单版是直接在
* FLASH_IDE上画以下三个 Dynamic TextField
*
* 此版本也可以这样,
* 但这里为了方便说明View
* 不直接在IDE上画
* 同时,一个Document Class
* 似乎也是不应该对引用其的FLA有接口限制(不知这样想对不对..)
*
*/
tf_hours = new TextField();
tf_minutes = new TextField();
tf_seconds = new TextField();
tf_hours.x = 120;
tf_minutes.x = 140;
tf_seconds.x = 160;
tf_hours.y=tf_minutes.y=tf_seconds.y = 100;
addChild(tf_hours);
addChild(tf_minutes);
addChild(tf_seconds);
}
private function runing() {
/******************
此函数与最简单版的AS一样
*******************/
var d:Date=new Date();
tf_hours.text=d.getHours().toString();
tf_minutes.text=d.getMinutes().toString();
tf_seconds.text=d.getSeconds().toString();
}
}
}
====================================================
====================================================
The version above just show a digital clock with 3 textfields ..
when you want a graphic version (有时针的那种,don't know how to spell it...)
you may need to rewrite all the code.
and each time you wanna change it's look,
you must repeat this....
actually, I don't think it's a trouble in this example(CLOCK)....
public class Time{
/**
* Model
*/
private var m_hours:uint;
private var m_minutes:uint;
private var m_seconds:uint;
public function Time(h:uint=0,m:uint=0,s:uint=0){
m_hours = h;
m_minutes = m;
m_seconds = s;
}
//
//以下函数个人认为
//在本例中不如直接把三个成员变量设为public方便
//
public function get hour():uint{return m_hours;}
public function set hour(h:uint):void{m_hours=h;}
public function get minute():uint{return m_minutes;}
public function set minute(m:uint):void{m_minutes=m;}
public function get second():uint{return m_seconds;}
public function set second(s:uint):void{m_seconds=s;}
/**原书注解,不翻译了..
* Note that the Time class also defines a clone() method
* that returns a new Time object
* with the same time value as the original.
* The clone() method is important so that
* we can assign clones of Time objects
* rather than references to the original.
*/
public function clone():Time{
return new Time(m_hours,m_minutes,m_seconds);
}
};
}
import flash.events.Event;
import flash.events.EventDispatcher;
//原书中还有:
// import gdutpxz.MVCLearing.Time
//在同一包内的类可以不引用,
//为什么在这书上却也引用?
//这有什么好处?不解...
public class ClockData extends EventDispatcher{
/**
* 此类继承于 EventDispatcher ,
* EventDispatcher类主要有 addListener 等函数
* 此类是FLASH库中实现的 观察者模式(observer pattern)
*/
private var m_time:Time;
public function ClockData(){
//
//书中例子是空的构造函数。
//个人认为构造函数应该进行数据初始化
//而非交给客户去完成
//
var d:Date = new Date();
m_time=new Time(d.getHours(),d.getMinutes(),d.getSeconds());
dispatchEvent(new Event(Event.CHANGE));
}
public function get time():Time{
if(m_time==null){
var d:Date=new Date();
return new Time(d.getHours(),d.getMinutes(),d.getSeconds());
}else{
/*
Time 类的clone函数在此应用.
原书注解:
In both cases where the ClockData class
uses the clone() method of Time objects,
it does so to protect encapsulation(封装性).
If it didn't call clone(),
but returned a reference to the object,
then any changes to that object outside the data model
would also affect the data model.
Consider the following example:
var data:ClockData = new ClockData();
var time:Time = new Time(12, 0, 0);
data.time = time;
time.hour = 14;
trace(data.time.hour);
(我的理解)
简而言之就是保护封装性,
使Model里的数据只能通过Model提供的方式来改变
本例中是 通过 setter function time() 来修改
*/
return m_time.clone();
}
}
public function set time(t:Time):void{
m_time=t.clone();
//下面这句即为observer模式的一个应用
//发出一个动作信号: CHANGE 给观查本对象的东西.
dispatchEvent(new Event(Event.CHANGE));
}
}//class ClockData
}//package gdutpxz.MVCLearing
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
public class AbstractClockView extends Sprite{
protected var m_data:ClockData;
public function AbstractClockView(d:ClockData){
m_data=d;
//
//当m_data调用了 dispatcherEvent(EVENT.CHANGE)时
// 本对象的 draw 函数执行.
//
m_data.addEventListener(Event.CHANGE,draw)
}
protected function draw(e:Event):void{
}
}//class AbstractClockView
}//package gdutpxz.MVCLearing
import flash.events.Event;
import flash.display.Sprite;
public class AnalogClock extends AbstractClockView{
/**
* 模拟挂钟
*/
private var m_face:Sprite;
private var m_hHand:Sprite; //时针
private var m_mHand:Sprite;
private var m_sHand:Sprite;
public function AnalogClock(data:ClockData){
super(data);
//===================================//
//画钟面
m_face = new Sprite();
m_face.graphics.lineStyle(0, 0x000000, 1);
m_face.graphics.drawCircle(0, 0, 100);
//画三条针
m_hHand = new Sprite();
m_hHand.graphics.lineStyle(5, 0x000000, 1);
m_hHand.graphics.lineTo(0, -50);
m_mHand = new Sprite();
m_mHand.graphics.lineStyle(2, 0x000000, 1);
m_mHand.graphics.lineTo(0, -80);
m_sHand = new Sprite();
m_sHand.graphics.lineStyle(0, 0x000000, 1);
m_sHand.graphics.lineTo(0, -80);
//===================================//
//添加到舞台(显示s)
//此处与书中代码略有不同
//原代码为 m_face 和三个hand都直接为
//主舞台的子元素。
//这里改成针为钟面的子元素.
m_face.addChild(m_hHand);
m_face.addChild(m_mHand);
m_face.addChild(m_sHand);
addChild(m_face);
//原文中还有一句 draw() 函数,
//此处省略,draw 函数的职能是响应 data的CHANGE事件,
//不应该直接调用
//从语义上说,data的构造函数应该触发 CHANGE事件。
//所以,回头改了ClockData的构造函数
}
//
//重写成员方法 draw
//
override protected function draw(e:Event):void{
//根据 m_data (继承自AbstractClockView的成员变量)
//绘制钟面的针的角度。
var time:Time = m_data.time;
//此处算法的公式,用初中的几何知识即可算出
m_hHand.rotation = 30*time.hour + 30*(time.minute/60);
m_mHand.rotation = 6*time.minute + 6*(time.second/60);
m_sHand.rotation = 6*time.second;
}
}//class AnalogClock
}//package gdutpxz.MVCLearing