BLOG main image
Category (342)
MySpace (89)
Astronomy (50)
Development (178)
Drum (25)
linux에서 subversion설정
누리에 없을 자그마한 자국
살라딘의 생각
saladin's me2DAY
3D Avata - BuddyPoke
기찬 개발이야기
[FLEX] ANT로 ASDOC 사용하기
THLIFE.net
Flash10 대응 Textcube 1.7.5.1..
텍스트큐브 공지사항
«   2008년 11월   »
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            
325609 Visitors up to today!
Today 109 hit, Yesterday 963 hit
/Development/Flex/AIR 관련글 보기 2007년 09월 20일 14시 44분
예전에 웹 서핑중에 학습하는데 도움이되는 컴포넌트를 발견하였다.
그것은 Peter Ent의 블로그에 올라온 게이지 컴포넌트였다.
잠시 구경해보자.

GaugeComponent.zip

원본소스다. 받아가삼~




1. Gauge 컴포넌트가 학습용으로 좋은 이유


난 이 Gauge 컴포넌트의 소스를 보자마자 컴포넌트 학습용으로 정말 좋다고 판단했다.
그 이유는 다음과 같다.

  1. 각종 스킨 타입을 제작 및 적용하는 방법을 학습할 수 있다.
    Gauge 컴포넌트는 단순히 UIComponent에 그래픽 속성만 부여하여 만들어진 컴포넌트가 아닌 Skin 및 style을 이용하여 다양한 모양의 Gauge를 만들어낼 수 있도록 만들었다. Gauge컴포넌트는 총 3부분으로 구성된다. 바늘(Needle), 바늘커버(Cover), 프레임(Frame) 이 그것이다. 이 구성을 PNG,JPG,SWF와 같은 그래픽 스킨 또는 프로그램적으로 만들어진 스킨(ProgrammaticSkin ,Border , 및 RectangularBorder 등을 확장함)을 적용이 가능하도록 되어 있다.
    사용자 삽입 이미지

    기본 프로그램 스킨

    사용자 삽입 이미지

    그래픽 이미지 스킨 적용

    사용자 삽입 이미지

    다른 프로그램 스킨 적용


  2. 컴포넌트 확장 학습을 할 수 있다.
    기본으로 만들어진 Gauge 컴포넌트는 바늘이 한개이다. 이를 확장하여 다음 그림과 같은 2개의 바늘을 가진 컴포넌트를 아주 쉽게 만들 수 있다.
    사용자 삽입 이미지
  3. Filter을 이용한 Grapic 학습에 도움을 준다.
    아래 그림의 Gauge는 실제로 Graphics 이용해 그림을 그리고 나서 BevelFilter를 이용해 음영 표현을 한것과 하지 않은 것을 보여주고 있다.
    사용자 삽입 이미지

    BevelFilter를 사용했을 때

    사용자 삽입 이미지

    Filter를 사용하지 않았을 때


2. 선행학습

컴포넌트를 제작하기 위해 먼저 ActionScript를 이용한 확장 컴포넌트를 만드는 방법에 대해서 먼저 학습할 필요가 있다. 특별히 UIComponent를 확장해서 만들것이므로 Flexdocs.kr 에서 제공하는 "확장된 컴퍼넌트의 작성에 대해"를 먼저 학습하기 바란다.

그리고 선행적으로 학습해야할 것은 스킨을 적용하는 방법이다. 아래 내용에 대해서 어느정도 숙지하고 있어야 Gauge컴포넌트를 이해하는데 도움이 된다. 아래 링크를 참고하여 필요한 지식을 얻자!

스킨의 종류


스킨 적용법



3. Gauge 컴포넌트 제작 방향 및 순서 선정

Gauge 컴포넌트는 일단 다음과 같은 방향으로 만들어 진다.

  1. 3개의 스킨(frameSkin, coverSkin, needleSkin)을 가진다.
  2. frame 배경색,투명도,경계선색,경계선투명도,경계선두께 스타일을 지정할 수 있다.
  3. cover의 색, 알파값, 커버의 그림자 유무을 스타일로 지정할 수 있다.
  4. 바늘(needle)의 색, 두께, 알파값을 스타일로 지정할 수 있다.
  5. 최대(maximum),최소값(minimum)을 설정할 수 있도록 한다.
  6. 값(value)를 설정할 수 있게 하고 Bind가 가능하게 한다.
  7. 바늘은 아래방향에서 좌측으로 45도을 최소값을 가리키게 하고 우측으로 315도 방향을 최대값을 가리키게 한다.
  8. 값(value)가 주어질 경우 바늘은 Rotate 이펙트를 이용해서 회전할 수 있도록 한다.
  9. LiveDrag의 속성(liveDragging)을 가지고 true이면 Gauge의 바늘을 마우스로 클릭하거나 드래그로 움직일 수 있다. 이때 gaugeClick 이벤트를 송출하도록 한다. 송출시 현재값과 새로운값을 넘겨준다.
  10. 바늘 하나를 더 추가한 DoubleGauge컴포넌트를 만들 수 있다.

위의 조건을 모두 만족하는 Gauge 컴포넌트를 만들기 위해 다음과 같은 순서로 제작한다.

  1. 프로그램 스킨을 이용한 기본스킨제작
    참고 : http://flexdocs.kr/docs/flex2/docs/00000808.html
  2. 마우스 클릭시 현재값과 새로운값을 송출하는 이벤트를 만든다.
  3. Gauge 컴포넌트를 만든다.
      - 스타일, 이벤트 메타데이타 지정
      - Skin 및 Rotate 이펙트 인스턴스  변수 선언
      - 생성자 : 마우스 이벤트 Listener
      - value, maximum, minmum, liveDragging 속성 setter, getter 제작
      - createChildren() : 스킨 인스턴스 생성 및 addChild, Rotate 이펙트 인스턴스 생성(target은 바늘이 된다.)
      - measure() : 기본 폭, 높이를 50으로 지정한다.
      - updateDisplayList() : 각 스킨의 위치 및 사이즈를 지정하고 값에 따라 바늘 각도에 따라 표시해줌, Cover의 그림자 효과 설정
  4. 위의 기본 Gauge를 적용해봄
  5. 다른 스킨 만들어봄 (네모모양, 다이얼형태)
  6. 바늘이 1개 더 추가된 Gauge 제작



4. 기본 스킨을 만들자.

스킨의 이름은 GaugeSkin 이라 정하자.
프로그램 스킨을 만들기 위해 부모 클래스로서 다음 3가지중 한개를 선택할 필요가 있다.
참고 : http://flexdocs.kr/docs/flex2/docs/00000809.html


Gauge예제에서는 Border 부모 클래스로 선택했다.
아래는 GaugeSkin 클래스의 기본골격이 되겠다.

GaugeSkin.as (Language : java)
package gauge.skins.programmatic
{
    import mx.skins.Border;
    import flash.display.Graphics;
    import mx.styles.StyleManager;
    import flash.filters.DropShadowFilter;

    public class GaugeSkin extends Border
    {
        public function GaugeSkin()
        {
            super();
        }
        override protected function updateDisplayList( w:Number, h:Number ) : void
        {
            //스타일 대응의 속성을 추가한다.
            //컴포넌트의 상태를 검출하는 논리를 추가해 속성을 설정
            //스킨 name에 따라 속성을 적용한 스킨의 기본 그림을 그려준다.
        }
    }

    private var _borderMetrics:EdgeMetrics;
    override public function get borderMetrics() :EdgeMetrics
    {
        //경계선의 두께를 알아내기 위한 속성의 값을 boarderMetrics형태로 반환하여 준다.
    }
}


위에서 두개의 메소드 updateDisplayList()와 borderMetrics()만 완성하면 되겠다.
먼저 borderMetircs() 메소드를 살펴보자. 이 메소드는 Border에 정의된 메소드로 재정의(override)해서 사용하면 된다. 경계선의 두께를 반환하면 되므로 스타일속성중 borderThickness값을 이용하면 되겠다.

Gauge.as의 borderMetircs() 메소드 재정의 (Language : java)
private var _borderMetrics:EdgeMetrics;
override public function get borderMetrics() :EdgeMetrics {
    var borderThickness:Number = getStyle("borderThickness");
    _borderMetrics = new EdgeMetrics(borderThickness, borderThickness,
        borderThickness, borderThickness);
    return _borderMetrics;
}

스타일 속성으로 배경색,배경투명도,경계선색,경계선두께,경계선투명도,바늘색,바늘두께,바늘투명도,커버색,커버투명도를 설정하기로 했다. 이들의 각각의 이름을 다음과 같이 정한다.

  • backgroundColor : frame의 배경색
  • backgroundAlpha : frame의 투명도
  • borderColor : frame의 경계선색
  • borderAlpha : frame의 투명도
  • borderThickness : frame의 두께
  • needleColor : 바늘의 색
  • needleAlpha : 바늘의 투명도
  • coverColor : 바늘 커버의 색
  • coverAlpha : 바늘 커버의 투명도

위에서 지정한 스타일 변수명은 이 GaugeSkin을 addChild하는 부모 클래스에서 정의한 Skin 메타데이타를 참고하게 된다.  부모 클래스에서는 GaugeSkin을 frameSkin이라는 Style명으로 사용한다고 가정할 때 아래와 같이 GaugeSkin을 사용하게 된다.

Gauge.as의 일부, GaugeSkin의 부모 클래스이다. (Language : java)
[Style(name="frameSkin",type="Class",inherit="no")]
...

[Style(name="backgroundColor",type="Number",format="Color",inherit="no")]

...
public class Gauge extends UIComponent
{
...
    override protected function createChildren():void
    {
        var skin:Class = Class(getStyle("frameSkin"));
        var newSkin:IFlexDisplayObject = new skin();

        newSkin.name = "frameSkin";
        newSkin.styleName = this;
       
        addChild(newSkin);
    }
...
}


위 코드의 중간에 newSkin는 GaugeSkin의 인스턴스가 되며 그 속성인 styleName에 this를 참조시키는 것을 볼 수 있다. 여기서 this는 부모 클래스를 의미한다. 이것을 하게 되면 GaugeSkin에서 getStyle()메소드를 통해 부모 클래스에서 설정한 Style명을 참고할 수 있다. 가령 위에 [Style(name="backgroundColor")]이 정의되어 있으므로 GaugeSkin에서 getStyle("backgroundColor")로 접근이 가능하다는 것이다.

GaugeSkin.as의 updateDisplayList() 메소드 (Language : java)
override protected function updateDisplayList( w:Number, h:Number ) : void
{
    var bgColor:Number = getStyle("backgroundColor");
    if( isNaN(bgColor) || !StyleManager.isValidStyleValue(bgColor)) bgColor = 0xFFFFFF;
    var bgAlpha:Number = getStyle("backgroundAlpha");
    if( isNaN(bgAlpha) || !StyleManager.isValidStyleValue(bgAlpha) ) bgAlpha = .85;
    var borderColor:Number = getStyle("borderColor");
    if( isNaN(borderColor) || !StyleManager.isValidStyleValue(borderColor) ) borderColor = 0x606060;
    var borderAlpha:Number = getStyle("borderAlpha");
    if( isNaN(borderAlpha) || !StyleManager.isValidStyleValue(borderAlpha) ) borderAlpha = 1;
    var borderSize:Number = getStyle("borderThickness");
    if( isNaN(borderSize) || !StyleManager.isValidStyleValue(borderSize) ) borderSize = 1;
    var needleColor:Number = getStyle("needleColor");
    if( isNaN(needleColor) || !StyleManager.isValidStyleValue(needleColor) ) needleColor = 0x000000;
    var needleThickness:Number = getStyle("needleThickness");
    if( isNaN(needleThickness) || !StyleManager.isValidStyleValue(needleThickness) ) needleThickness = 3;
    var needleAlpha:Number = getStyle("needleAlpha");
    if( isNaN(needleAlpha) || !StyleManager.isValidStyleValue(needleAlpha) ) needleAlpha = 1;
    var coverColor:Number = getStyle("coverColor");
    if( isNaN(coverColor) || !StyleManager.isValidStyleValue(coverColor) ) coverColor = 0x606060;
    var coverAlpha:Number = getStyle("coverAlpha");
    if( isNaN(coverAlpha) || !StyleManager.isValidStyleValue(coverAlpha) ) coverAlpha = 1;
   
    var g:Graphics = graphics;
   
    g.clear();
   
    // the name property determines which skin is being drawn.

    switch( name )
    {
        case "frameSkin":
            g.lineStyle( borderSize, borderColor, borderAlpha );
            g.beginFill( bgColor, bgAlpha );
            g.drawEllipse(x,y,w,h);
            g.endFill();
            break;
        case "needleSkin":
            g.lineStyle( needleThickness, needleColor, needleAlpha );
            g.moveTo(0,0);
            g.lineTo(Math.min(w,h)*.45,0);
            break;
        case "coverSkin":
            g.lineStyle( 0, 0, 0 );
            g.beginFill( coverColor, coverAlpha );
            g.drawEllipse((w-w/4)/2,(h-h/4)/2,w/4,h/4);
            g.endFill();
            break;
    }
}


작성된 updateDisplayList()메소드를 분석하자.
크게 두부분으로 나뉜다. Style값을 획득하는 부분과 Skin name에 따라서 그림을 그려주는 부분이다.

윗 부분을 살펴보면 아래와 같은 코드가 반복되는 것을 볼 수 있다.
    var bgColor:Number = getStyle("backgroundColor");
    if( isNaN(bgColor) || !StyleManager.isValidStyleValue(bgColor)) bgColor = 0xFFFFFF;

이 부분은 부모클래스에서 정의한 Style명 backgroundColor 의 값을 getStyle()메소드로 읽고 있다. 하지만 부모에서 유효한 값을 사용하지 않았거나, 값이 지정되지 않았다면 bgColor를 기본값으로 0xFFFFFF로 해준다.

위 코드에서 아래 부분을 살펴보자.
아래 부분은 GaugeSkin의  name 속성의 값이 frameSkin, needleSkin, coverSkin 일때 서로 다른 그림을 그려준다.  잘 보면 name속성이 frameSkin인 경우 해당 Style속성인 backgroundColor, backgroundAlpha, borderThickness, borderColor, borderAlpha값을 이용하여 정해진 폭과 높이에 따라 타원모양을 배경에 그려주고 있다. 같은 방법으로 needleSkin인 경우 전체크기의 약 45%정도의 바늘크기를 가진 선을 그려주고
coverSkin일때는 바늘을 덮어줄 수 있도록 중심부분에 전체 폭,높이에 대해 약 1/4 크기의 타원형 cover를 그려준다. 프로그램 스킨에서 그림을 그리는 방법 및 적용방법에 대해서는 프로그램스킨>프로그램에 의한 묘화 를 참고하면 되겠다.

부모 클래스에서는 이 GaugeSkin을 3개 인스턴스화해서 각각 이름을 frameSkin, needleSkin, coverSkin으로 하여 addChild하게 된다.


5. 이벤트를 만들자.

만들어질 이벤트는 Gauge에서 마우스 이벤트가 발생했을때 현재값과 새로운 값을 담는 역할을 한다.
그 외에는 별 내용이 없으므로 소스만 확인해보자.

GaugeEvent.as (Language : java)
package gauge.events
{
    import flash.display.InteractiveObject;
    import flash.events.MouseEvent;

    public class GaugeEvent extends MouseEvent
    {
        public function GaugeEvent(currentValue:Number, value:Number, localX:Number=0, localY:Number=0, relatedObject:InteractiveObject=null, ctrlKey:Boolean=false, altKey:Boolean=false, shiftKey:Boolean=false, buttonDown:Boolean=false, delta:int=0.0)
        {
            super("gaugeClick", true, true, localX, localY, relatedObject, ctrlKey, altKey, shiftKey, buttonDown, delta);
            this.currentValue = currentValue;
            this.value = value;
        }
       
        public var currentValue:Number;
        public var value:Number;
       
    }
}


6. Gauge 컴포넌트를 만들자.

앞서 GaugeSkin의 부모인 Gauge의 약간 맛배기로 보았다. Gauge는 UIComponent를 확장하여 사용할 것이다.
6-1 Style 및 이벤트 메타데이터 지정 & needle 회전이펙트 및 Skin 인스턴스 참조 변수 선언

아래는 Gauge가 가져야 하는 기본 구조와 Style 및 Event 메타데이타를 정의한 코드이다.
앞서 지정한 GaugeSkin에 대한 Class를 참고해야하므로 Style 메타데이타에 frameSkin, coverSkin, needleSkin을 정의했다. type은 Class이다.

그리고 이미 지정한 Style의 이름과 type 및 format을 지정한다.

class에 private변수로 frameSkin, coverSkin, needleSkin을 IFlexDisplayObject로 선언했다.
앞서 메타데이터로 지정한 frameSkin, coverSkin, needleSkin 스타일에 대응하여 이 변수에 인스턴스가 생성되게 된다. 이 메타데이터는 우리가 앞서 정의한 GaugeSkin일 수 있고 이미지 또는 다른 Skin이 될 수 있겠다.

Gauge.as의 기본구조. (Language : java)
package gauge
{
    ....

    [Style(name="frameSkin",type="Class",inherit="no")]
    [Style(name="coverSkin",type="Class",inherit="no")]
    [Style(name="needleSkin",type="Class",inherit="no")]

    [Style(name="backgroundColor",type="Number",format="Color",inherit="no")]
    [Style(name="backgroundAlpha",type="Number",inherit="no")]
    [Style(name="borderColor",type="Number",format="Color",inherit="no")]
    [Style(name="borderAlpha",type="Number",inherit="no")]
    [Style(name="borderThickness",type="Number",nherit="no")]
    [Style(name="needleColor",type="Number",format="Color",inherit="no")]
    [Style(name="needleThickness",type="Number",inherit="no")]
    [Style(name="needleAlpha",type="Number",inherit="no")]
    [Style(name="coverColor",type="Number",format="Color",inherit="no")]
    [Style(name="coverAlpha",type="Number",inherit="no")]
    [Style(name="coverDropShadowEnabled",type="Boolean",inherit="no",default="true")]

    [Event(name="gaugeClick",type="gauge.events.GaugeEvent")]
   
    public class Gauge extends UIComponent
    {   
        protected var frameSkin:IFlexDisplayObject;
        protected var coverSkin:IFlexDisplayObject;
        protected var needleSkin:IFlexDisplayObject;
       
        private var rotate:Rotate; 

        public function Gauge()
        {
            super();
            ....
        }

        override protected function createChildren():void
        {
            super.createChildren();
            ....
        }

        override protected function measure():void
        {
            super.measure();
            ....
        }

        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            super.updateDisplayList(unscaledWidth,unscaledHeight);
            ....
        }

        ....
    }
}


6-2 스킨적용

스킨을 addChild해야하므로 UIComponent의 createChildren() 메소드를 재정의해서 사용한다.
아래 코드에서 보면 이미 선언한 3개 스킨 변수에 createSkin()함수를 이용하여 인스턴스를 생성하는 것을 볼 수 있다. createSkin()메소드가 하는 일은 1번째 인자로 스킨이름으로 스킨이 이미 만들어져 있는지 검사후 만약 없으면 기본 스킨 클래스인 GaugeSkin 클래스를 적용하게 한다.

Gauge를 인스턴스를 사용할때 <gauge:Gauge id="g1" /> 형태로 사용하면 createSkin()메소드는 GaugeSkin를 이용해 Skin 인스턴스생성한다. 하지만 만약 <gauge:Gauge id="g1" frameSkin='@Embed(source="/gauge/skins/graphic/BitmapFrame.png')"/>와 같은 형태로 사용하게 되면 frameSkin 스타일의 인스턴스로 BitmapFrame.png를 Embed한 Class를 이용하게 되는 것이다. 또 다른 형태의 프로그램 스킨을 만들었다면 <gauge:Gauge id="g1" frameSkin='@ClassReference("gauge.skins.alternatives.DialSkin')"/>
와 같은 형태로 frameSkin을 적용할 수 있겠다. 여기서 DialSkin도 GaugeSkin처럼 만들어졌다고 생각하면 된다.

아래 프로그램에서 중요한 점은 바로
styleableSkin.styleName = this;
이다.
styleName을 this로 안해주면 BaseSkin또는 다른 프로그램 스킨에서 Gause.as에서 정의한 스타일 메타데이타 값들을 getStyle()로 참조할 수 없다.

Gauge.as - 스킨을 addChild하는 부분 (Language : java)
override protected function createChildren():void
{
    super.createChildren();
   
    frameSkin  = createSkin( "frameSkin", GaugeSkin );
    needleSkin = createSkin( "needleSkin", GaugeSkin );
    coverSkin  = createSkin( "coverSkin", GaugeSkin );
   
    rotate = new Rotate(needleSkin);
}

protected function createSkin( skinName:String, defaultSkin:Class ) : IFlexDisplayObject
{
    var newSkin:IFlexDisplayObject =
        IFlexDisplayObject(getChildByName(skinName));
   
    if (!newSkin)
    {
        var newSkinClass:Class = Class(getStyle(skinName));
        if( !newSkinClass ) newSkinClass = defaultSkin;
       
        if (newSkinClass)
        {
            newSkin = IFlexDisplayObject(new newSkinClass());
            if( !newSkin ) newSkin = new defaultSkin();
           
            newSkin.name = skinName;

            var styleableSkin:ISimpleStyleClient = newSkin as ISimpleStyleClient;
            if (styleableSkin)
                styleableSkin.styleName = this;

            addChild(DisplayObject(newSkin));
        }
    }
   
    return newSkin;
}


6-3 게이지 그리기

아래 코드를 보자. 앞서 인스턴스화하고 addChild 한 frameSkin, needleSkin, coverSkin의 배치하고 있다. 특별히 coverSkin인 경우 Style 속성중 coverDropShadowEnabled가 true일때 cover의 그림자 효과를 주고 있다.
또한 needleSkin인 경우 value값에 따라 회전하고 있으며 이때 회전효과를 주기 위해 Rotate 이펙트 인스턴스를 사용하는 것을 볼 수 있다.

여기서 중요한 부분은 바로 Skin들 자체가 컴포넌트화 되어서 사용되었다는 점이다.
더욱 생각해야할 부분은 이 스킨들이 우리가 만든 GauseSkin뿐 아니라 Gauge를 인스턴스화 할때 Style을 어떻게 해주냐에 따라 전혀 다른 모습을 보여줄 수 있다는 것이다.

Gauge.as - updateDisplayList() 재정의 (Language : java)
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
    super.updateDisplayList(unscaledWidth,unscaledHeight);
   
    var coverDropShadowEnabled:Object = getStyle("coverDropShadowEnabled");
   
    // positin and size the skins.
    frameSkin.move(0,0);
    frameSkin.setActualSize(unscaledWidth,unscaledHeight);
   
    // the needle skin has its origin moved to the very center
    // of the component; makes rotating it easy.
    needleSkin.move(unscaledWidth/2,unscaledHeight/2);
    needleSkin.setActualSize(unscaledWidth,unscaledHeight);
   
    // the cover has its origin moved to the center of the
    // component, too.
    coverSkin.move( 0, 0 );
    coverSkin.setActualSize( unscaledWidth, unscaledHeight );
    if( coverDropShadowEnabled == null || coverDropShadowEnabled == true ) {
        DisplayObject(coverSkin).filters = [ new DropShadowFilter(4,45,0,.5) ];
    }
   
    // adjust the value to make sure it is within bounds.
    if( _value < _minimum ) _value = _minimum;
    if( _value > _maximum ) _value = _maximum;
   
    // determine the angle of the needle based on the current
    // value and minimum and maximum values.
    var angle:Number = calculateAngleFromValue(_value);
   
    // Use a Rotate effect to spin the needle from its previous
    // position.

    if( rotate.isPlaying ) rotate.end();
    rotate.angleFrom = _prevAngle;
    rotate.angleTo = angle;
    rotate.originX = 0;
    rotate.originY = 0;
    rotate.play();
   
    _prevAngle = angle;
}

그 외에 마우스 컨트롤하는 부분과 getter, setter 정의에 대한 설명은 생략한다.
여기서 설명하고자 하는 주제와 약간 벗어날 수 있기 때문이다. 이에 대해서는 개별적으로 소스를 분석해봤으면 한다.


7. GaugeSkin만 적용한 Gauge 컴포넌트를 사용해보자.

아래와 같이 Gauge를 테스트하는 프로그램을 만들었다.
첫번째 게이지는 어떤 스타일도 적용하지 않은 기본 게이지이다. 라이브 Drag가 되고 Drag 할때 두번째 게이지의 값과 연동되도록 했다. 두번째와 세번째는 인라인방법과 스타일시트를 이용한 방법을 이용해 스타일을 적용했다.

GaugeText.mxml (Language : xml)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:gauge="gauge.*">
    <mx:Style>
        .needle {
            coverColor:   #009900;
            needleColor:        #009900;
            borderColor:        #009900;
            borderThickness:    3;
            backgroundColor:    #FFFFFF;
            backgroundAlpha:    .85;
            coverDropShadowEnabled: false;
        }
    </mx:Style>
   
    <mx:Script>
    <![CDATA[
        import mx.controls.Alert;
        import gauge.events.GaugeEvent;
        private function handleGaugeEvent( event:GaugeEvent ) : void
        {         
            g2.value = event.value;
        }
    ]]>

    </mx:Script>
    <gauge:Gauge id="g1" x="20" y="20" width="100" height="100"
        gaugeClick="handleGaugeEvent(event)"
        liveDragging="true"
        value="300"
        minimum="200"
        maximum="600"      
         />

    <mx:Text x="20" y="122" width="100" text="Programmatic, Basic, Interactive"/>
        
    <gauge:Gauge id="g2" x="200" y="20" width="100" height="100"
        backgroundColor="0xFFFFFF"
        backgroundAlpha=".4"
        borderColor="0xDD0000"
        borderAlpha="1"
        borderThickness="4"
        needleColor="0x000000"
        needleThickness="4"
        needleAlpha=".7"
        coverColor="0xDD0000"
        coverAlpha="1"
        value="300"
        minimum="200"
        maximum="600"/>

    <mx:Text width="100" x="200" y="122" text="Programmatic, Styled"/>
        
    <gauge:Gauge id="g3" x="352" y="10" width="100" height="100"
        styleName="needle"
        value="{stepper.value}"/>

    <mx:Text width="100" x="352" y="120" text="Programmatic, Styled"/>
        
    <mx:Label x="20" y="197" text="Set value:"/>
    <mx:NumericStepper id="stepper" x="95" y="195" minimum="0" maximum="100" />
</mx:Application>
 






8. Embed 이미지를 frame과 cover에 적용해보기

아래와 같은 두개의 이미지를 준비하여 Embed하는 방법을 통해서 Gauge의 스킨을 적용할 수 있다.
그렇게 되면 frameSkin과 coverSkin에 GaugeSkin의 인스턴스를 대신하여 Embed된 이미지가 적용이된다. 물론 그렇게 할경우 최종적인 swf파일이 용량이 커지게 된다.

사용자 삽입 이미지

BitmapCover.png

사용자 삽입 이미지

BitmapFrame.png


GaugeText.mxml - 이미지를 Embed하여 Skin에 적용 (Language : xml)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:gauge="gauge.*">
    <mx:Style>
        .bitmapGauge {
            frameSkin:    Embed(source="/gauge/skins/graphic/BitmapFrame.png");
            coverSkin:    Embed(source="/gauge/skins/graphic/BitmapCover.png");
            needleColor:        #ff99c0;
        }
    </mx:Style>
    <gauge:Gauge id="g3" x="10" y="10" width="100" height="100"
        styleName="bitmapGauge"
        value="{stepper.value}"/>

    <mx:Text width="100" x="10" y="118" text="Graphic"/>
        
    <mx:Label x="10" y="146" text="Set value:"/>
    <mx:NumericStepper id="stepper" x="85" y="144" minimum="0" maximum="100" />
</mx:Application>



 

9. 다이얼 형태의 프로그램 스킨 만들어보기 


기본적으로 제공되는 GaugeSkin대신 Dial형태의 Skin을 만들어보겠다. 다이얼 형태는 아래 그림처럼 coverSkin과 needleSkin이 붙어있으므로 이중 한가지만 그림을 그리면 되는데, Rotate 이펙트가 needleSkin에 적용되므로 needleSkin만 그리면 되겠다. 무슨 말인지는 아래 해당 코드를 보면 쉽게 알 수 있을것이다.

DialSkin은 GaugeSkin과 다르게 updateDisplayList()에서 Gauge에서 정의된 Style속성을 전혀 사용하지 않고 단독적으로 색,굵기,투명도등을 가지고 있다. 즉, 외부에서 Style속성값을 적용시킬려고 해도 적용시킬 수 없다는 뜻이다. Style속성을 적용하기 원한다면 DialSkin을 GaugeSkin처럼 수정하면 되겠다.

또 특이한 점은  name이 framsSkin과 needleSkin일때만 그림을 그린다. coverSkin은 그림을 그리지 않고 있다. 즉, DialSkin에서는 coverSkin의 존재가 무의미하기 때문이다.

filters에 BevelFilter 를 쓰고 있기 때문에 DialSkin을 좀더 볼륨감있게 표현할 수 있다.
제작한 DialSkin은 아래와 같은 방법으로 ClassReference를 이용해 적용하면 되겠다.

GaugeText.mxml - DialSkin 적용 (Language : xml)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:gauge="gauge.*">
    <mx:Style>
        .dialGauge {
            frameSkin:    ClassReference("gauge.skins.alternatives.DialSkin");
            coverSkin:    ClassReference("gauge.skins.alternatives.DialSkin");
            needleSkin:  ClassReference("gauge.skins.alternatives.Dia