Monthly Archive for January, 2007

Custom Interval Class

<Interval Class>

import com.dstrict.UB.events.Dispatcher;
import com.dstrict.UB.management.IntervalEvent;
/**--------------------------------------------------------------------------------
* @description 인터벌 생성및 실행 클래스
*    원하는 함수를 사용자가 원하는 횟수만큼 호출한후 onIntervalEnd 를 발행시킴...
*
* @implement
*   Interval#onIntervalEnd
*
* @example
* <code>
*  _interval=new Interval();
 _interval.addEventListener(IntervalEvent.ON_INTERVAL_END,this);
 _interval.makeInterval(functionScope,functionReference,duration,loop,[parameter array]);
 
 public function onIntervalEnd(evt:IntervalEvent):Void{
    // 인터벌 이후에 이벤트를 사용하려면 구현...
     parameter array 인자가 그대로 넘어온다...
 
  }
* </code>
*
*--------------------------------------------------------------------------------*/
class com.dstrict.UB.management.Interval extends Dispatcher{
 private var _IntervalID : Number;
 private var _count : Number;
 
  /**------------------------------------------------------------------------------
     * Constructor function
   *------------------------------------------------------------------------------*/
 public function Interval() {
  //생성자 함수 필요없음....
 }
 
 /**------------------------------------------------------------------------------
 * @description 전역속성인 setInterval 함수의 id 값 전부 제거
 *-------------------------------------------------------------------------------*/
 public static function clearAllInterval():Void{
  var topId=setInterval(function(){
  },100);
  for(var i=0 ; i&lt;=topId; i++){    clearInterval(i);   }  }       
/**------------------------------------------------------------------------------    
 * @description interval 에의한 실행함수     
* @param loop : Number, 함수 실행할 횟수     
*@param referObj : Object, 인터벌에 등록한 함수 오브젝트    
 *-------------------------------------------------------------------------------*/   
public function execute(loop:Number,referObj:Object):Void{      if(_count&gt;loop){
        clearInterval(_IntervalID);
       _count=1;
     startEvent(new IntervalEvent(IntervalEvent.ON_INTERVAL_END,referObj.param)); //Dispatch  event
     }else{
        if(referObj!=undefined){
           referObj.func.apply(referObj.obj,referObj.param);
         }
         _count++;
      }
    }
 
 /**-----------------------------------------------------------------------------
 * @description  인터벌 생성
 * @param scope : Object, 실행할 함수의 스코프
 * @param func : Function, 실행할 함수
 * @param duration : Number, 인터벌 간격(밀리세컨드)
 * @param loop : Number, 함수 실행할 횟수
 *-------------------------------------------------------------------------------*/
 public function makeInterval(scope:Object,func:Function,duration:Number,
                                            loop:Number,parameter:Array):Void{
 
   clearInterval(_IntervalID);
   _count=1;
  _IntervalID=setInterval(this,"execute",duration,loop,{func:func,obj:scope,param:parameter});
 
 }
}

<DispatcherClass>

import mx.events.EventDispatcher;
/**
* @description     이벤트 디스패처 확장 클래스
*                        이벤트 발생할 클래스에 상속후 startEvent 함수 실행.....
*/
class com.dstrict.UB.events.Dispatcher {
public var dispatchEvent:Function;
public var addEventListener:Function;
public var removeEventListener:Function;
public function Dispatcher() {
EventDispatcher.initialize(this);
}
public function startEvent(obj : Object) : Void {
dispatchEvent(obj);
}
}

자주사용하는 인터벌을 쓰기 편하게 클래스로 만들었다.  원하는 함수를 원하는 횟수만큼 호출한후 자동으로 인터벌이 삭제된다. 함수 호출시 파라미터도 같이 호출할 수도 있고 인터벌이후에 발생하는 이벤트도 실행할 수도 있게 구성했다.

<example code>
test 함수를 문자열 2개 인자와 함께 200 millisecond 간격으로 5번 호출한다.

_interval=new Interval();
_interval.addEventListener(IntervalEvent.ON_INTERVAL_END,this); --> 인터벌이후에 발생하는이 벤트를 받기위해서 리스너를 붙인다. 받을 이벤트가 없다면 필요없다.
_interval.makeInterval(this,test,200,5,["test string1......","test string2......"]);
 
function test(str:String,str2:String):Void{
trace(str);
trace(str2);
}
function onIntervalEnd(evt:IntervalEvent):Void{
// 인터벌 이후에 이벤트를 사용하려면 구현...
// evt 값은 makeInterval 에서 test 함수를 호출할때 같이 쓰인 문자열 인자값이 배열로 그대로 들어온다.
// evt.target[0] -----> test string1...... evt.target[1] -----> test string2......
}

Bound methods in AS3.0

<These quotes are from the Actionscript 3.0 language reference>

A bound method, sometimes called a method closure, is simply a method that is extracted from its instance. Examples of bound methods include methods that are passed as arguments to a function or returned as values from a function. New in ActionScript 3.0, a bound method is similar to a function closure in that it retains its lexical environment even when extracted from its instance. The key difference, however, between a bound method and a function closure is that the this reference for a bound method remains linked, or bound, to the instance that implements the method. In other words, the this reference in a bound method always points to the original object that implemented the method. For function closures, the this reference is generic, which means that it points to whatever object the function is associated with at the time it is invoked.
Understanding bound methods is important if you use the this keyword. Recall that the this keyword provides a reference to a method’s parent object. Most ActionScript programmers expect that the this keyword always refers to the object or class that contains the definition of a method. Without method binding, however, this would not always be true.
In previous versions of ActionScript, for example, the this reference did not always refer to the instance that implemented the method. When methods are extracted from an instance in ActionScript 2.0, not only is the this reference not bound to the original instance, but also the member variables and methods of the instance’s class are not available. This is not a problem in ActionScript 3.0 because bound methods are automatically created when you pass a method as a parameter. Bound methods ensure that the this keyword always references the object or class in which a method is defined.

The following code defines a class named ThisTest, which contains a method named foo() that defines the bound method, and a method named bar() that returns the bound method. Code external to the class creates an instance of the ThisTest class, calls the bar() method, and stores the return value in a variable named myFunc.

class ThisTest {
private var num:Number = 3;
function foo () { // bound method defined
trace ("foo's this: " + this);
trace ("num: " + num);
}
function bar () {
return foo; // bound method returned
}
}
var myTest:ThisTest = new ThisTest();
var myFunc:Function = myTest.bar();
trace(this); // output: [object global]
myFunc();
/* output:
foo's this: [object ThisTest]
output: num: 3 */

The last two lines of code show that the this reference in the bound method foo() still
points to an instance of ThisTest class, even though the this reference in the line just before
it points to the global object. Moreover, the bound method stored in the myFunc variable still
has access to the member variables of the ThisTest class. If this same code is run in
ActionScript 2.0, the this references would match and the num variable would be undefined.
<These quotes are from the Actionscript 3.0 language reference>

도큐먼트 문서에서 개인적으로 AS3.0 이 새롭게 지원하는 기능중에 가장 좋았던 것 중에 하나다.
더이상 중첩된 메서드 안에서 클래스 안에 선언된 메서드의 참조값을 알아내기 위해 지역변수로 참조를 하지 않아도 된다.
코드 가독성 측면에 있어서 좋지 않았었는데 이젠 끝까지 메서드 선언된 참조 위치를 가지고 있으니 파라미터나 리턴 값에 의해 참조값이 바뀔 염려는 없어진 셈이다.

How to implement User RectBorder

플래시에서 제공되는 component 들은 종류에 비해 디자인적인 확장성에서 제약이 있기 때문에 많이 사용되지 않고 있다. 물론 나도 특별한 경우를 제외하고는 사용하지 않는 편이다.
나름대로 디자인에 큰 영향이 없다면 제공되는 기본 component 를 사용하지만 간혹가다 뜻하지 않는 문제점에 부딛히게 되면 여간 힘든게 아니다. 많이 사용해 보지 않는 문제점을 해결하는 것이 만만치 않다. 특히 기본 component 를 사용할때 가장 문제가 되는것이 바로 border 처리 문제일것이다.
halo theme 에서 제공되는 border를 쓰자니 디자인에 걸릴때가 참 많이 발생하게 된다.
물론 theme 파일을 수정하여 요소들을 수정할 수 있지만 여간 손이 많이 가는게 아닐 뿐더러 자칫하면 내장 클래스를 건드리게 되어 플래시 전체의 component 의 UI 가 뜻하지 않게 될수도 있다.

이런 저런 문제로 그동안 사용을 극도로 꺼려했지만 이번에 러퍼런스를 보고 가장 손쉽게 border 를 사용자가 맞게 구성하는 방법을 찾아내어 소개해 본다.

기본적인 방법은 내장 component 에서 사용하는  RectBorder 을 편집하여 사용자가 만든 border 를 사용할 수 있게 하는 것이다.

1. 플래시가 설치되어 있는 폴더에서 Class/mx/skins 폴더에 사용자 정의 테두리에 사용할 사용자 정의 패키지 이름으로 새 폴더를 만든다.
ex: C:\Program Files\Macromedia\Flash 8\en\First Run\Classes\mx\skins
2. 이폴더에 RectBorder.as 이름으로 사용자 정의 클래스를 만든다.
3.다음 코드를 삽입한다.

import mx.core.ext.UIObjectExtensions;
class mx.skins.myTheme.RectBorder extends mx.skins.RectBorder {
static var symbolName:String = "RectBorder";
static var symbolOwner:Object = RectBorder;
var className:String = "RectBorder";
#include "../../core/ComponentVersion.as"
// All of these borders have the same size edges, 1 pixel.
var offset:Number = 4;
function init(Void):Void {
super.init();
}
function drawBorder(Void):Void {
// The graphics are on the symbol's timeline,
// so all you need to do here is size the border.
_width = __width;
_height = __height;
}
// Register the class as the RectBorder for all components to use.
static function classConstruct():Boolean {
UIObjectExtensions.Extensions();
_global.styles.rectBorderClass = RectBorder;
_global.skinRegistry["RectBorder"] = true;
return true;
}
static var classConstructed:Boolean = classConstruct();
static var UIObjectExtensionsDependency = UIObjectExtensions;
}

위코드는 사용자 정의 Symbol 을 사용하여 사용자가 정의한  RectBorder을 사용하여 border를 설정하는 것이다.

4. 새로운 Symbol 을 생성한 후  linkage property 에서 아래와 같이 설정한다.
Identifier :  RectBorder
As 2.0 Class : mx.skins.myTheme.RectBorder

5. 조금전에 생성한 RectBorder symbol 을 편집해 원하는 border 를 그린다.
단지 좌표값을 0,0 에 맞추어 속이 빈 사각형 박스를 그리기만 하면 된다.

6. RectBorder를 사용하는 여러 component 요소를 스테이지로 드래그합니다.
예를 들어 List, TextArea 및 TextInput component
7. export movie 를 통해 확인해 보면 자신이 만든 border 사용하여 그려진 것을 볼 수 있다.

이런 방법을 사용하면 전체적으로  borderStyle 에 영향받지 않고 자신이 원하는 border 를 구성할 수 있을 것이다.

How to sort Objects(Class)

sortOn (Array.sortOn method)

public sortOn(fieldName:Object, [options:Object]) : Array

Sorts the elements in an array according to one or more fields in the array. The array should have the following characteristics:

  • The array is an indexed array, not an associative array.
  • Each element of the array holds an object with one or more properties.
  • All of the objects have at least one property in common, the values of which can be used to sort the array. Such a property is called a field.If you pass multiple fieldName parameters, the first field represents the primary sort field, the second represents the next sort field, and so on. Flash sorts according to Unicode values. (ASCII is a subset of Unicode.) If either of the elements being compared does not contain the field that is specified in the fieldName parameter, the field is assumed to be undefined, and the elements are placed consecutively in the sorted array in no particular order.오브젝트를 일반적인 단일속성이 아닌 한개 이상의 여러 속성을 기준으로 정렬할시 사용되는 메서드이다. 오브젝트를 정렬할때 종종 사용하던 방법이였는데 이번 프로젝트를 진행하면서 클래스 자체를 정렬할때 사용해 보았는데 제대로 작동하였다.

    클래스는 당연히 오브젝트의 일종이다. 따라서 클래스 안에 있는 멤버 변수들을 기준으로 정렬이 가능하다는 의미다. 자신이 클래스를 사용하여 이미지 갤러리같은 정렬의 기능이 있는 컨텐츠를 제작할시에 아주 유용한 기능일 것이다.

    // widget class : 정렬에 사용될 클래스

    class com.dstrict.UB.project.ces2007.widget.Widget {
      public var _id:String;
      public var _title:String;
      public var _date:Number;
      public function Widget(id:String,title:String,date:Number) {
      _id=id;
      _title=title;
      _date=date;
    }
    }
    // example code
     
    import com.dstrict.UB.project.ces2007.widget.Widget ;
    var widgetArr:Array=new Array();
    var widget1:Widget=new Widget("vkimone","widget1",20061213);
    var widget2:Widget=new Widget("kimkijeung","widget2",20061110);
    var widget3:Widget=new Widget("Tom","widget3",20061115);
    var widget4:Widget=new Widget("Jane","widget4",20061211);
    widgetArr.push(widget1);
    widgetArr.push(widget2);
    widgetArr.push(widget3);
    widgetArr.push(widget4);
    for(var i=0; i<widgetArr.length ; i++){
    trace(i+"  : "+widgetArr[i]._id+" : "+widgetArr[i]._title+"  ----------->"+widgetArr[i]._date);
     
    trace("======================================");
    widgetArr.sortOn("_date",Array.NUMERIC| Array.DESCENDING);
    for(var i=0; i<widgetArr.length ; i++){
    trace(i+"  : "+widgetArr[i]._id+" : "+widgetArr[i]._title+"  ----------->"+widgetArr[i]._date);
    }

    //result
    0  : vkimone : widget1  ———–>20061213
    1  : kimkijeung : widget2  ———–>20061110
    2  : Tom : widget3  ———–>20061115
    3  : Jane : widget4  ———–>20061211
    ======================================
    0  : vkimone : widget1  ———–>20061213
    1  : Jane : widget4  ———–>20061211
    2  : Tom : widget3  ———–>20061115
    3  : kimkijeung : widget2  ———–>20061110

    각각의 아이디값과 제목 그리고 날짜 정보를 포함하는 widget 클래스에서 여러개의 객체를 생성한후
    배열에 넣은 다음 오브젝트 속성인 _date 를 기준으로 내림차순으로 숫자 정렬했을때의 결과값이다.
    각 클래스 속성을 기준으로 통채로 정렬이 된다.

    만역 클래스를 이용해 철저히 오브젝트들을 캡슐화(encapsulation)했다면 손쉽게 오브젝트 정렬을 사용할 수 있을 것이다.