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            
325641 Visitors up to today!
Today 141 hit, Yesterday 963 hit
/Development/Flex/AIR 관련글 보기 2007년 10월 26일 17시 14분


먼저 위 프로그램의 흰배경색의 컴포넌트(UIComponent를 확장) 위에 마우스 커서를 얹어보자. 각종정보가 담겨있는 박스가 마우스 커서를 따라 다닌다. 흰배경색 컴포넌트를 Drag도 해보자. 이런 Action을 취하면서 동시에 정보표시창의 정보가 어떻게 변하는지 유심히 살펴보자. ComboBox를 다른 것으로 선택하고 앞서 했던 일을 반복하면서 선행했던 동작과 비교해보자.

프로그램 소스



MyUIComponent.as (Language : java)
/*
    제작자 : 지용호(http://blog.jidolstar.com/, jidolstar@gmail.com)
    제작일 : 2007-10-26
   
    본 예제 컴포넌트는
    컴포넌트 위에 마우스를 따라 움직이는 정보창(여기서는 TextArea)을 보여줘야 할때
    어떤방법으로 보여줘야 하는가 보여주는 예제입니다.
   
    단순한 예제이지만 UIComponent를 기반 컴포넌트 만드는 방법, 이벤트 전파방법,
    각종 마우스 관련 위치 속성(stageX, localX, mouseX등..) 에 대해
    정확히 파악하고 있어야 해결할 수 있는 문제입니다.
   
    관련 학습은 http://flexdocs.kr 에서 하시기 바랍니다.
*/

package
{
    import mx.core.UIComponent;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.events.MouseEvent;
    import mx.controls.TextArea;

    public class MyUIComponent extends UIComponent
    {
        //TextField에 사용될 문구
        private var arrText:Array = ["flex","jidolstar.com","flexdocs.kr","astronote.org"];  
       
        //마우스를 쫗아다니며 정보를 보여줄 TextArea
        private var textArea:TextArea;
       
        //생성자
        public function MyUIComponent()
        {
            super();
            addEventListener( MouseEvent.MOUSE_DOWN, mouseEventHandler);
            addEventListener( MouseEvent.MOUSE_MOVE, mouseEventHandler);
            addEventListener( MouseEvent.MOUSE_OVER, mouseEventHandler);
        }

        //UIComponent 라이프 사이클에 의해 자동적으로 호출됨
        //초반에 자식을 등록할려면 이 함수를 오버라이드해서 사용한다.
        override protected function createChildren():void
        {
            var textField:TextField;
            var r:uint;
            var g:uint;
            var b:uint;
            var color:uint;
            var i:int=0;
           
            // TextField를 자식으로 추가한다.
            for each( var text:String in arrText)
            {
                i++;
                r = Math.random() * 0xff;
                g = Math.random() * 0xff;
                b = Math.random() * 0xff;
                color = (r<<16 | g<<8 | b); //랜덤 글자색
                textField = new TextField;
                textField.text = text;
                textField.name = "textField"+i;
                textField.setTextFormat( new TextFormat( null, 18, color ) );
                textField.background = true;    //backgroundColor를 적용할려면 background=true이어야 한다.
                textField.backgroundColor = 0xeeeeee;
                textField.border = true;    //borderColor를 적용할려면 border=true이어야 한다.
                textField.borderColor = 0x1023dd;
                textField.width = textField.textWidth+5;    //폭을 글자폭에 맞춘다.
                textField.height = textField.textHeight+5//높이를 글자높이에 맞춘다.
                textField.visible = false//초반에는 안보여줌, updateDisplayList에서 true로 설정됨
                textField.selectable = false;   //선택하지 못하게 한다. 커서 I모양이 없어짐
                addChild(textField);
            }
           
            //마우스를 따라 정보를 보여줄 TextArea를 자식으로 추가한다.
            if( textArea == null )
            {
                textArea = new TextArea;
                textArea.setStyle("borderColor", 0xff0000);
                addChild(textArea);
            }
        }
   
        //MXML상에서 명시적으로 width와 height를 정해주면 measure()함수를 호출되지 않는다.
        //크기 변동이 있는 경우가 생길경우 오버라이드 해서 사용한다.
        override protected function measure():void
        {
            super.measure();
            measuredWidth = measuredMinWidth = 500;
            measuredHeight = measuredMinHeight = 500;
        }
       
        //그림을 그리는 함수, 초반에 자동적으로 호출된다.
        //invalidateDisplayList()를 호출하면 자동으로 호출됨
        //자식의 위치와 크기를 조정하여 그림을 그려주는 역할을 함
        //인자로 스케일링이 적용되지 않은 폭과 높이가 넘어옴
        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            super.updateDisplayList(unscaledWidth, unscaledHeight);
           
            //정해진 크기에 맡게 직사작형 배경을 그려줌.
            //그려주는 이유는 시각적으로 보여주기 위한 것도 있지만
            //만약 그리지 않으면  MouseEvent를 받을 수 있는 영역이 없게 된다.
            graphics.clear();
            graphics.lineStyle(1, 0x000000, 1.0);
            graphics.beginFill(0xfefefe, 1.0);
            graphics.drawRect(0,0,unscaledWidth, unscaledHeight);
            graphics.endFill();
           
            //자식으로 둔 textField를 random한 위치에 그려준다.
            var i:int;
            var x:Number;
            var y:Number;
            var textField:TextField;
            for( i=0; i < numChildren; i++)
            {
                textField = this.getChildAt(i) as TextField;
                if( textField )
                {
                    x = Math.random() * (unscaledWidth - textField.width);
                    y = Math.random() * (unscaledHeight - textField.height);
                    textField.x = x;
                    textField.y = y;
                    textField.visible = true;
                }
            }
        }
       
        //마우스 핸들러 함수
        private var draging:Boolean=false;
        private function mouseEventHandler( event:MouseEvent ):void
        {
            switch( event.type )
            {
                case MouseEvent.MOUSE_DOWN:
                    //Drag 시작
                    startDrag();
                    draging = true;
                    removeEventListener( MouseEvent.MOUSE_DOWN, mouseEventHandler);
                    addEventListener( MouseEvent.MOUSE_UP, mouseEventHandler);
                    break;
                   
                case MouseEvent.MOUSE_OUT:
                    //Mouse가 Out할경우 정보표시 TextArea를 보여주지 않음
                    if( textArea )
                    {
                        textArea.visible = false;   
                        addEventListener( MouseEvent.MOUSE_OVER, mouseEventHandler);
                        removeEventListener( MouseEvent.MOUSE_OUT, mouseEventHandler);
                    }
                    break;
                   
                case MouseEvent.MOUSE_OVER:
                    //Mouse가 In할경우 정보표시 TextArea를 보여줌
                    if( textArea )
                    {
                        textArea.visible = true;
                        addEventListener( MouseEvent.MOUSE_OUT, mouseEventHandler);
                        removeEventListener( MouseEvent.MOUSE_OVER, mouseEventHandler);
                    }
                    break;
                   
                case MouseEvent.MOUSE_MOVE:
               
                    //드래그 중인데(즉, startDrag()를 호출했음) buttonDown이 안된경우
                    //강제로 MOUSE_UP을 시킴, stopDrag()를 호출시켜주기 위함
                    //이러한 경우는 Drag중 마우스가 화면밖에 나갔다가 다시 들어온 경우를 처리해주기 위함이다.
                    if( event.buttonDown == false && draging == true)
                        dispatchEvent( new MouseEvent(MouseEvent.MOUSE_UP, true, false, event.localX, event.localY));

                    // mouseEventHandler함수는 this에만 event listener를 등록했으므로
                    // event.currentTarget은 무조건 this이다. event.currentTarget == this는 없어도 됨   
                    if( textArea && event.currentTarget == this)
                    {
                        // 영역내에 있을 때에 정보표시 TextArea가 보여져 있을 것이다.
                        if( textArea.visible == true )
                        {
                            var x1:Number;
                            var y1:Number;

                            //_mousePosition값에 따라서 정보표시 TextArea의  위치(x,y)값을 설정한다.
                            switch(_mousePosition)
                            {
                                case MOUSE_EVENT_STAGE_POSITION:
                                    x1 = event.stageX;
                                    y1 = event.stageY;
                                    break;
                                case MOUSE_EVENT_LOCAL_POSITION:
                                    x1 = event.localX;
                                    y1 = event.localY;
                                    break;
                                case MOUSE_COMPONENT_POSITION:
                                    x1 = mouseX;
                                    y1 = mouseY;
                                    break;
                            }
                           
                            //정보를 표시한 내용
                            var text:String;
                            text =  "event.target.name = " + event.target.name +"\r" +
                                    "event.currentTarget.name = " + event.currentTarget.name + "\r" +
                                    "event.localX = " + event.localX + "\r" +
                                    "event.localY = " + event.localY + "\r" +
                                    "event.stageX = " + event.stageX + "\r" +
                                    "event.stageY = " + event.stageY + "\r" +
                                    "this.mouseX = " + mouseX + "\r" +
                                    "this.mouseY = " + mouseY + "\r";
                                   
                            //정보표시 TextArea의 정보와 위치, 크기 조정시킴
                            textArea.text = text;
                            textArea.setActualSize( 300,130 );
                            textArea.move( x1+10, y1+10 );
                        }
                    }
                    break;
                   
                case MouseEvent.MOUSE_UP:
                    //Mouse_UP하는 경우 Drag를 중지시킴
                    removeEventListener( MouseEvent.MOUSE_UP, mouseEventHandler);
                    addEventListener( MouseEvent.MOUSE_DOWN, mouseEventHandler);
                    stopDrag();
                    draging=false;
                    break;
            }
        }
       
        //정보표시 TextArea의 위치를 어떤 마우스 위치 관련 속성을 가지고 참조할 것인가 선택
        public static const MOUSE_EVENT_STAGE_POSITION:String = "stage"; //MouseEvent의 stageX, stageY를 이용
        public static const MOUSE_EVENT_LOCAL_POSITION:String = "local"; //MouseEvent의 localX, localY를 이용
        public static const MOUSE_COMPONENT_POSITION:String = "comp";   //UIComponent의 mouseX, mouseY를 이용
        private var _mousePosition:String = MOUSE_COMPONENT_POSITION;
        public function set mousePosition( value:String ):void
        {
            switch(value)
            {
                case MOUSE_EVENT_STAGE_POSITION:
                case MOUSE_EVENT_LOCAL_POSITION:
                case MOUSE_COMPONENT_POSITION:
                    _mousePosition = value;
                    break;
            }
        }
    }
}


ExMousePosition.mxml (Language : xml)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:ns1="*" name="application">
    <ns1:MyUIComponent id="testComponent" x="10" y="40" width="279" height="213"/>
    <mx:ComboBox id="cbMousePos" x="10" y="10" change="testComponent.mousePosition = cbMousePos.selectedItem.value">
        <mx:Object label="mouseX, mouseY" value="{MyUIComponent.MOUSE_COMPONENT_POSITION}"/>
        <mx:Object label="stageX, stageY" value="{MyUIComponent.MOUSE_EVENT_STAGE_POSITION}"/>
        <mx:Object label="localX, localY" value="{MyUIComponent.MOUSE_EVENT_LOCAL_POSITION}"/>
    </mx:ComboBox>
</mx:Application>
 



프로그램 설명


위 프로그램은 UIComponent를 확장하여 Mouse를 이용해 Drag가 가능하도록 했다. 그리고 그 위에 마우스가 움직일 때, MouseEvent의 localX, localY, stageX, stageY정보 및 currentTarget, target정보를 TextArea를 이용해 보여주고 있다. 이 정보표시 TextArea는 마우스의 위치를 따라 다니게 만들어졌다. 정보표시하는 TextArea는 확장한 UIComponent의 자식이다. 또한 4개의 TextField를 임의의 위치에 자식으로 등록했다.

이 프로그램의 제작 목적은 위에 기술한 그대로 이다. 특히 중요한 점은 정보표시 TextArea가 확장한 UIComponent 내부에서만 마우스를 잘 따라다녀줘야 한다는 점이다.
이때 문제없이 구현하기 위해서 사용해야할 마우스 관련 위치정보는 어떤 것이 있을까?

1. UIComponent의 mouseX, mouseY - DisplayObject의 속성이다.
2. MouseEvent에 stageX, stageY
3. MouseEvent에 localX, localY

결론부터 말한다면 위 문제를 해결하기 위해 1번의 확장한 UIComponent(this)의 mouseX, mouseY를 사용해야한다는 것이다. (만약 다른 방법이 있다면 댓글 부탁한다.)



2번 경우 - stageX, stageY 사용하기
위 프로그램에서 ComboBox에서 StageX, StageY를 선택해보자. 확장한 UIComponent 의 좌측상단을 화면의 좌측상단에 가져다 놓고 사용하면 mouseX, mouseY를 사용한 것과 똑같은 동작을 한다. 하지만 UIComponent를 임의의 위치로 움직이면 정보표시 TextArea가 마우스와 떨어지는 것을 확인할 수 있다.

사용자 삽입 이미지


이유는 MouseEvent의 stageX, stageY는 global영역에서의 위치정보이고 정보표시 TextArea는 확장UIComponent의 자식이기 때문이다. 그래서 확장한 UIComponent의 좌측상단을 프로그램의 좌측상단에 위치 시키면 mouseX,mouseY를 선택한 것과 같은 동작을 한다.


3번 경우 - localX, localY 사용하기

localX, localY를 사용하면 어떨까?
(localX, localY는 MouseEvent를 일으킨 target 위에서의 마우스 위치이다. )
확장한 UIComponent는 4개의 TextField와 한개의 정보표시 TextArea를 자식으로 두고 있다. 이 자식들을 피해서 확장한 UIComponent 위에서만 마우스를 움직이면 1번 경우처럼 mouseX,mouseY를 사용한 것과 동일한 동작을 한다. 하지만 UIComponent의 자식인 TextField위에 마우스가 올라가면 이상한 동작을 하게 된다.
확장 UIComponent가 아닌 그의 자식에 마우스가 올라가면 확장 UIComponent에 대한 localX, localY가 아닌 자식들의 localX와 localY가 된다. 아래 그림을 보면 쉽게 이해할 수 있겠다.

사용자 삽입 이미지

1번 경우 - mouseX, mouseY 를 이용
1번의 경우처럼 확장한 UIComponent의 mouseX, mouseY 속성을 이용하면 위와 같은 문제점이 발생하지 않는다. MouseEvent가 발생할때마다 정보표시 TextArea의 x,y값을 mouseX, mouseY로 적용만 하면 되기 때문이다.


마무리

단순한 예제이지만 UIComponent를 기반 컴포넌트 만드는 방법, 이벤트 전파방법, 각종 마우스 관련 위치 속성(stageX, localX, mouseX등..) 에 대해 정확히 파악하고 있어야 해결할 수 있는 문제이다.
소스를 정확히 분석해보고 이해할 필요가 있겠다.

컴포넌트를 만들다보면 각종 속성에 대해서 정확히 이해할 필요가 생긴다.
초반에 Flex를 하는 사람에게는 이러한 정보자체를 알아내기가 정말 쉽지 않다.
나도 마찬가지였고, 아주 단순한 정보지만 삽질끝에 얻어낸 정보이다.
그러기에 유용한 정보가 되었으면 한다.


학습사이트

Flex/AIR 한글화 페이지 http://flexdocs.kr


글쓴이 : 지돌스타(http://blog.jidolstar.com/257)


이 글의 관련글
Trackback Address :: http://blog.jidolstar.com/trackback/257
BlogIcon 검쉰 | 2007년 10월 29일 10시 39분 | PERMALINK | EDIT/DEL | REPLY
그렇죠.. 삽질해야 정확하게 알 수 있는 부분. ㅋㅋ
Name
Password
Homepage
Secret