태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.
밤하늘의 실제별, 나도 가질 수 있다?!

[Flex] MXML에서 사용하는 Non Visual 컴포넌트 제작 - IMXMLObject 활용

2008/08/12 10:17

 

[공지]이미지나 링크가 깨졌다면 댓글 부탁드립니다.

IMXMLObject에 대해서 잘못 이해한 부분이 있다.
문제는 IMXMLObject를 확장해야 MXML용 Non Visual 컴포넌트를 만들 수 있다고 언급한 부분인데.. 그것 자체가 잘못되었다. ActionScript로 어떻게 만들어도 MXML환경에서 사용할 수 있다. 가령, <mx:Object/>처럼 말이다. Object는 IMXMLObject를 구현하지 않았다. 그래도 MXML환경에서 사용할 수 있다. 이 말은 즉, MXML환경에서 사용할 수 있는 컴포넌트를 만들기 위해 IMXMLObject를 사용하는 것이 아니라는 말이다. 결국 Non Visual 컴포넌트를 만들때 IMXMLObject를 이용하는 이유는  IMXMLObject.initilized() 메소드의 역할때문이다. 이에 관련해서 조만간 글을 올리겠다.

아래 "추가사항"부터는 틀린 내용이 아니므로 참고해도 되겠다.

잘못된 정보를 올려서 죄송합니다. ^^;


컴포넌트에는 크게 Visual 컴포넌트와 Non-visual 컴포넌트가 있다.

Visual 컴포넌트는 말 그래도 눈에 보이는거다.
즉, Button, DataGrid와 같은 컴포넌트를 의미한다.

Non-visual Component는 안보이는 컴포넌트이다.
HttpService와 같은 컴포넌트를 의미한다.

특별히 Non-visual Component이면서 MXML로 사용할 수 있는 컴포넌트를 만들 수 있다.
HttpService가 대표적인 예다.
Flex SDK에서 HttpServce를 보면 mx.rpc.http.HTTPService와 mx.rpc.http.mxml.HttpService가 있다.
mx.rpc.http.mxml.HttpService는 아래와 같이 mx.rpc.http.HTTPService를 확장한 형태이다.
그러면서 IMXMLSupport와 IMXMLObject Interface를 구현하고 있다.

public class HTTPService extends mx.rpc.http.HTTPService implements IMXMLSupport, IMXMLObject
{
....
}

그럼 mx.rpc.http.HTTPService과 mx.rpc.http.mxml.HttpService의 구체적인 차이점은 무엇인가?
바로 MXML 환경에서 <mx:HttpService>처럼 사용할 수 있는가 없는가의 차이이다.
mx.rpc.http.mxml.HttpService는 ActionScript 뿐 아니라 MXML에서도 사용할 수 있지만 mx.rpc.http.HTTPService는 ActionScript에서만 사용이 가능하다.

mx.rpc.http.mxml.HttpService이 MXML환경에서 사용할 수 있게 되게 하는 것은 바로
IMXMLObject 를 구현했기 때문이다.

(잘못 알고 있었다. 어떻게 만들던지 MXML환경에서 사용할 수 있다. 구체적인 차이점은 바로 IMXMLObject.initialized()의 역할을 활용하는가 안하는가의 차이이다. 이 메소드를 이용하면 속성의 초기화를 일괄적으로 수행할 수 있다는 장점을 가진다. 즉, MXML환경에서 최적화된 컴포넌트를 만들 수 있다는 말이다. 아래를 계속 읽어보면 그 이유를 알 수 있을 것이다.)


IMXMLObject의 구조는 매우 단순하다.

package mx.core

{

public interface IMXMLObject

{

function initialized(document:Object, id:String):void;

}

}


initialized() 한개만 구현하면 MXML에서 사용할 수 있다는 의미를 가진다. 
IMXMLObject를 활용하면 MXML 환경에서도 Non visual 컴포넌트를 붙힐 수 있다.


<?xml version="1.0" encoding="utf-8"?>

<mx:Object xmlns:mx="http://www.adobe.com/2006/mxml" implements="mx.core.IMXMLObject">

       <mx:Script>

             <![CDATA[

                    private var document:Object;

                    private var id:Object;

            

                    public function initialized( document:Object, id:String ):void

                    {

                           this.document = document;

                           this.id = id;

                           trace("x=" + x + ",y=" + y + ",z="+z);

                    }

             ]]>

       </mx:Script>

       <mx:Number id="x"/>

       <mx:Number id="y"/>

       <mx:Number id="z"/>

</mx:Object>

위의 코드를 ActionScript로 표현하면 다음과 같을 것이다.

package

{

       import mx.core.IMXMLObject;

      

       public class NonVisualObject implements IMXMLObject

       {

             private var document:Object;

             private var id:Object;

            

             [Bindable]

             public var x:Number;

 

             [Bindable]

             public var y:Number;

 

             [Bindable]

             public var z:Number;

 

             public function NonVisualObject()

             {

             }

            

             public function initialized( document:Object, id:String ):void

             {

                    this.document = document;

                    this.id = id;

                    trace("x=" + x + ",y=" + y + ",z="+z);

             }

       }

}


이렇게 작성한 Non Visual 컴포넌트를 아래와 같이 Application에 MXML 형태로 사용할 수 있게 된다.

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*">

       <local:NonVisualObject x="1" y="2" z="3" id="nvo"/>

</mx:Application>

결과는 아래와 같다.
x=1,y=2,z=3

이 결과는 무엇을 의미하는가?
x, y, z와 같은 정의한 컴포넌트의 속성을 초기화한 다음에 IMXMLObject의 initialized() 메소드가 호출된다는 것을 의미한다. 이 말은 속성의 값이 모두 설정된 다음에 initilized() 함수안에서 그 속성값을 가지고 다른 작업을 할 수 있다는 것을 말한다.

initialized() 메소드 2개의 인자는 document:Object와 id:String 이다. 위 코드대로라면 document는 Application의 인스턴스 값이 되고 id는 Application에서 설정한 id가 된다. 즉, 위 코드경우 id는 nvo가 된다.  


만약 Non Visaul 컴포넌트를 MXML로 사용할 수 없게 만들면 아래 예와 같이 더 복잡하게 <mx:Script>안에 사용해야할 것이다.

package

{

       public class NonVisualObject    

{

             private var document:Object;

             private var id:Object;

            

             [Bindable]

             public var x:Number;

 

             [Bindable]

             public var y:Number;

 

             [Bindable]

             public var z:Number;

 

             public function NonVisualObject()

             {

             }

            

            

             public function result():void

             {

                    trace("x=" + x + ",y=" + y + ",z="+z);

             }

       }

}

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*" initialize="init()">

       <mx:Script>

             <![CDATA[

                    private var nonVisualObject:NonVisualObject;

                    private function init():void

                    {

                           nonVisualObject = new NonVisualObject();

                           nonVisualObject.x = 1;

                           nonVisualObject.y = 2;

                           nonVisualObject.z = 3;

                           nonVisaulObject.result();

                    }

             ]]>

       </mx:Script>

</mx:Application>

결과는 아래와 같다.
x=1,y=2,z=3


같은 결과를 내기 위해 IMXMLObject를 사용한 것과 사용하지 않은 것이 이렇게 다르다.
MXML 상에서 Non Visual 컴포넌트를 사용해야될 필요성이 있을때는 IMXMLObject를 잊지 말고 활용하길 바란다.



- 추가사항 -

IMXMLObject의 initialized() 메소드의 메커니즘

연찬익(http://blog.empas.com/chaniks/)님께서 IMXMLObject의 initialized() 메소드의 메커니즘을 간단하게 설명해 주셔서 더 추가한다.

이 메커니즘을 살펴보기 위해 아래에서 설명하는 과정이 필요하다.
Flex 컴파일러는 MXML을 ActionScript로 변환한 후에 그런 다음 SWF로 컴파일한다.
Flex Builder에서 -keep-generated-actionscript을 컴파일 옵션으로 넣으면 된다.

방법은 Flex Builder에서 자신의 프로젝트를 선택후 오른쪽 버튼을 눌러 Context 메뉴가 뜨면 맨 아래 Properties를 선택한다. 창이 뜨면 왼쪽 메뉴에서 Flex Compiler를 선택한다. 오른쪽에 Additional compiler arguments에 -keep-generated-actionscript를 추가후 ok버튼을 누르면 MXML에서 ActionScript로 변환된 모습을 src폴더 generated 폴더에서 확인할 수 있다.


사용자 삽입 이미지

사용자 삽입 이미지


나는 간단히 테스트를 하기 위해 프로젝트 MyProj라는 이름으로 생성했다.
그리고 MyProj.mxml을 다음과 같이 만들었다.


<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*">

       <local:NonVisualObject x="1" y="2" z="3" id="nvo"/>

</mx:Application>


NonVisualObject는 다음과 같이 코딩했다.(앞서 보여줬던 코드다.)

<?xml version="1.0" encoding="utf-8"?>

<mx:Object xmlns:mx="http://www.adobe.com/2006/mxml" implements="mx.core.IMXMLObject">

       <mx:Script>

             <![CDATA[

                    private var document:Object;

                    private var id:Object;

 

                    public function initialized( document:Object, id:String ):void

                    {

                           this.document = document;

                           this.id = id;

                           trace("x=" + x + ",y=" + y + ",z="+z);

                    }

             ]]>

       </mx:Script>

       <mx:Number id="x"/>

       <mx:Number id="y"/>

       <mx:Number id="z"/>

</mx:Object>


위 코드는 모두 MXML로 작성된 것을 볼 수 있다.

generated 폴더안에 작성된 MyProj-generated.as와 NonVisualObject-generated.as를 보면 작성한 MXML이 어떻게 ActionScript로 변경되었는가 알 수 있다.

특별히 IMXMLObject.initialized() 메소드가 호출되어지는 부분 또한 MyProj-generated.as에서 확인할 수 있다.


private function _MyProj_NonVisualObject1_i() : NonVisualObject

{

       var temp : NonVisualObject = new NonVisualObject();

       nvo = temp;

       temp.x = 1;

       temp.y = 2;

       temp.z = 3;

       temp.initialized(this, "nvo")

       return temp;

}


즉, IMXMLObject로 구현되어진 컴포넌트를 사용하면 Flex Compiler가 자동으로 이런코드로 변환시켜준다는 것이다. 참 멋진 Flex다.


mx.core.UIComponentDescriptor

UIComponent를 확장해서 만들어진 Button, CheckBox, Panel과 같은 Visual Component의 경우에는 mx.core.UIComponentDescriptor가 자동으로 생성된다.


사용자 삽입 이미지


위 화면처럼 배치했다고 가정하자.
그럼 gererated 폴더안에 MyProj-generated.as를 보면 다음과 같은 코드가 만들어져 있는 것을 볼 수 있을 것이다.

       //     Container document descriptor

private var _documentDescriptor_ : mx.core.UIComponentDescriptor =

new mx.core.UIComponentDescriptor({

  type: mx.core.Application

  ,

  propertiesFactory: function():Object { return {

    childDescriptors: [

      new mx.core.UIComponentDescriptor({

        type: mx.controls.Button

        ,

        propertiesFactory: function():Object { return {

          x: 53,

          y: 98,

          label: "Button"

        }}

      })

    ,

      new mx.core.UIComponentDescriptor({

        type: mx.controls.CheckBox

        ,

        propertiesFactory: function():Object { return {

          x: 210,

          y: 122,

          label: "Checkbox"

        }}

      })

    ,

      new mx.core.UIComponentDescriptor({

        type: mx.containers.Panel

        ,

        propertiesFactory: function():Object { return {

          x: 53,

          y: 173,

          width: 250,

          height: 200,

          layout: "absolute",

          childDescriptors: [

            new mx.core.UIComponentDescriptor({

              type: mx.controls.Button

              ,

              propertiesFactory: function():Object { return {

                x: 10,

                y: 10,

                label: "Button"

              }}

            })

          ,

            new mx.core.UIComponentDescriptor({

              type: mx.controls.ComboBox

              ,

              propertiesFactory: function():Object { return {

                x: 10,

                y: 40

              }}

            })

          ]

        }}

      })

    ]

  }}

})

 



살펴볼 것은 바로 mx.core.UIComponentDescriptor이다. 이 클래스는 UIComponent를 확장하여 MXML로 작성된 모든 Visual 컴포넌트 정보를 가지고 있는 역할을 한다. 자세히 보면 이 안에는 이벤트, 스타일, 속성 정보가 모두 포함되는 것을 확인할 수 있다.


***Style.as 로 끝맺는 Class들의 정체

_ButtonStyle.as 를 살펴보자.

 

package

{

 

import flash.display.Sprite;

import mx.core.IFlexModuleFactory;

import mx.core.mx_internal;

import mx.styles.CSSStyleDeclaration;

import mx.styles.StyleManager;

import mx.skins.halo.ButtonSkin;

 

[ExcludeClass]

 

public class _ButtonStyle

{

 

    public static function init(fbs:IFlexModuleFactory):void

    {

        var style:CSSStyleDeclaration = StyleManager.getStyleDeclaration("Button");

   

        if (!style)

        {

            style = new CSSStyleDeclaration();

            StyleManager.setStyleDeclaration("Button", style, false);

        }

   

        if (style.defaultFactory == null)

        {

            style.defaultFactory = function():void

            {

                this.paddingTop = 2;

                this.textAlign = "center";

                this.skin = mx.skins.halo.ButtonSkin;

                this.paddingLeft = 10;

                this.fontWeight = "bold";

                this.cornerRadius = 4;

                this.paddingRight = 10;

                this.verticalGap = 2;

                this.horizontalGap = 2;

                this.paddingBottom = 2;

            };

        }

    }

}

 

}

이것을 보고 무엇을 알아냈는가?
StyleManager를 이용해 Button Type Selector에 기본 스타일을 먹이고 있다는 것을 알 수 있다.
즉, Flex 컴파일러는 Flex SDK에서 제공하는 기본 Visual 컴포넌트들에 대해서 Default 스타일을 먹일 수 있도록 ActionScript 코드를 자동으로 생성해 준다는 것이다.

코드 안에 this.skin = mx.skins.halo.ButtonSkin을 보자.
이 것은 ProgrammaticSkin을 확장한 mx.skins.halo.ButtonSkin을 Button의 기본스킨으로 쓰고 있다는 것을 보여준다. 나는 예전에 Button의 기본 스킨이 Button자체에서 설정되는가 Button.as를 뒤진적이 있었다. 결국 못찾았었는데.... 이렇게 숨겨져 있을 줄은 몰랐었다. ㅎㅎㅎ


참고 블로그
검쉰 : [Flex] MXML은 어떻게 AS로 변환되는가? (Event Handler 에 파라미터 넣기)
시난 : [팁] mxml이 as로 변환되는 과정 확인
연찬익 : IMXMLObject.initialized()의 메카니즘. 



이 부분은 Flex 개발자라면 반드시 알아야할 내용이다.
MXML이 어떻게 ActionScript와 연관이 되는가 알 수 있는 유용한 정보이겠다.
시간만 된다면 더 파헤쳐 봐야겠다. 이에 대한 글도 많이 올라왔으면 한다.


글쓴이 : 지돌스타(http://blog.jidolstar.com/357)
크리에이티브 커먼즈 라이선스
Creative Commons License

Adobe Flash Platform , , , , , ,

Trackback 주소: http://blog.jidolstar.com/trackback/357
  1. 2008/08/11 20:35
    IMXMLObject.initialized()의 메카니즘. Tracked from 연찬익 / Flex Developer
  1. Blog Icon
    동강

    오 딱 궁금해 하고 있던 부분을 콕 찝어 주시는군요.

  2. 아직도 궁금증이 남아있답니다. ㅎ

  3. 좋은 글입니다. ;)
    저도 IMXMLObject 인터페이스에 대해서 궁금했었는데 말이죠 ㅎ

  4. 감사합니당

  5. 저도 예전에 httpService로 개발하면서 저 두녀석의 차이점을 단순히 mxml로 사용하기 위해 확장한 녀석과 as로 사용하기 위한 녀석정도로만 알고 있었는데~~^^; 제 수박 겉핥기식 지식 습득이 창피할 정도로 좋은 글입니다 ㅎㅎㅎ

  6. 저도 그럴때가 많은 걸요 ^^;;;
    가끔 하다보면 궁금해져서 파고 들면 뭔가 알아낸다는...
    그게 재미있는 것 같습니다.

  7. Blog Icon
    닷넷나무

    지돌아저씨한테는 언제나 감사하고 있습니다.
    아무것도 모르고 플렉스 프로젝트 투입되서 지금까지 살아 남을 수 있었던건...
    지돌아저씨 덕분이라 생각합니다. 꾸벅꾸벅

  8. 제 글이 도움이 되었다니 저도 기쁩니다.
    제 블로그에 올라오는 글들은 제가 Flex를 하면서 공부한 것들을 정리합니다. 제가 실무에서 직접 필요한 것만 올리기 때문에 도움이 될 수 밖에 없을 것 같아요. 그런데 Flex도 워낙 스케일이 커서 해도해도 끝이 없네요. ㅎㅎㅎ 그래서 혼자하는 것은 정말 벅차요. 그래서 많은 Flex 프로그래머들이 자신의 블로그를 만들고 함께 정보를 공유했으면 하는 바램입니다.

  9. 우와....그러지 않아도 여기저기 뒤지다가 저게 뭔가 싶었는데...조만간 공부하고 싶었던 부분이었는데...그야말로 지돌님 블로그는 바이블 덩어리~~

  10. 과찬이십니다. ^^
    감사합니다.

  11. 글들이 꼬리에 꼬리를 물고 확장되니 알찬 정보들이 되네요 ;)
    즐겁습니다 ㅎㅎ

  12. 블로깅의 묘미죠. ^^

  13. 공유할 수록 커지는 정보들 >_<

  14. 공유하는 사람들만이 이 느낌을 알 수 있다는거~ ㅎ

  15. 지돌스타님 인기에 묻어가는 즐거움 ㅎㅎㅎ; 덩실덩실~

  16. 인기요? ㅎㅎ
    인기보다 실력이 우선인 것 같습니다. ^^
    찬익님 많이 가르쳐 주세요. ^^

  17. 앗.. 제가 말 실수를..;
    지돌스타님 탄탄한 실력에 어찌 제가 ㅎㅎ;
    앞으로도 좋은 포스팅 많이 기대하겠습니다. :'D

  18. ㅎㅎ 이미 파악했습니다.
    잘하시는거 제가 아는데요 ㅎ

  19. 지돌/검쉰/시난/찬익 고수님들 말씀대로 공유 할 수록 꼬리에 꼬리를 물고 커지는 정보들을 보면서 이게 바로 WEB 이구나...라는 생각을 다시 하게 됩니다.
    감사를 모르고 퍼왔던 정보들이 이제는 그 앞에서 숙연해 지기까지 합니다.

  20. 별말씀을요... 부족하기에 열심히 관리하는 블로깅입니다.
    다른분들이 있기에 좋은 글이 나오는 것 같습니다.

  21. Blog Icon
    php2년

    지돌스타님 자료 잘보고 배우고 있습니다 감사합니다 ^^;

    다름이 아니라 한가지 질문좀 드려도 될까요.. 이미지에디터에서.. 이미지를 편집하고 원래대로 돌리는 기능은 historymanager를 이용하는게 맞는건가요? 아님 다른 방법으로 구현이 가능한건가요.. 영어도 약하고 ㅠ.ㅠ 도움좀 부탁드려요~

  22. 따로 만듭니다.
    언제 history로 등록할지도 결정해야하고요.

  23. Blog Icon
    고고당

    오늘도 좋은글 읽고 갑니다. ^^ 감사해요