달력

4

« 2024/4 »

  • 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
2013. 1. 10. 10:10

Flex DataGrid ItemRenderer #3 Enjoy/FLEX2013. 1. 10. 10:10

출처 : http://igna84.blogspot.kr/2010/03/flex-datagrid-itemrenderer-3-%EB%98%90%EB%8B%A4%EB%A5%B8-%EC%A0%84%EC%9F%81%EC%9D%98-%EC%84%9C%EB%A7%89.html



Flex DataGrid ItemRenderer #3- 또다른 전쟁의 서막

지난 시간 제기한 문제점은 아래와 같았습니다.

 

1. "Y", "N" 값으로만 작동하게 되어있다.

2. CheckBox를 클릭하면 뭔가 다른 행동을 하고 싶을땐 어떻게 하나.

 

외부에서 들어오는 데이터가 "0"이나 "1"이면 어떻한다?(혹은 true 나 false일지도..)

CheckBox를 클릭하면 Alert 창이 떠야한다면?

 

이럴때마다 ItemRenderer를 열어서 수정해야한다면 말이 안되겠지요.

일단 2번 같은 경우는 제가 알기로는 두가지 방법이 있습니다만 그중 하나는 Bubbles라는 이벤트 속성을 이용하는 방법입니다만 ItemRenderer에서 이벤트를 발생시키면서 bubbles 속성을 true로 지정해주면 DataGrid 밖에서 이벤트를 받아올 수 있지요.

다만.. bubbles라는 녀석의 특성상 데이터가 많이 꼬일 염려가 있다는게 문제입니다.

(꼬인다는건 "디버깅"이 어려워질 수 있다는 말을 쉽게 풀어 쓴 말입니다.)

 

그래서 저는 가장 확실한 방법으로 CallBack 함수를 지정해 놓는 방법을 선택했습니다.

아래의 코드를 봐주세요.

 

Main.mxml
[code xml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:renderers="classes.controls.renderers.*">
<mx:Script>
    <![CDATA[
    import mx.collections.ArrayCollection;
    import mx.controls.Alert;

    [Bindable]
    private var ac:ArrayCollection = new ArrayCollection([
                                        {index:1, description:"test1", toggle:"Y"},
                                        {index:2, description:"test2", toggle:"N"},
                                        {index:3, description:"test3", toggle:"N"},
                                        {index:4, description:"test4", toggle:"Y"},
                                        {index:5, description:"test5", toggle:"N"},
                                        {index:6, description:"test6", toggle:"N"},
                                        {index:7, description:"test7", toggle:"Y"},
                                        {index:8, description:"test8", toggle:"N"},
                                        {index:9, description:"test9", toggle:"N"},
                                        {index:10, description:"test10", toggle:"N"},
                                        {index:11, description:"test11", toggle:"N"},
                                        {index:12, description:"test12", toggle:"N"}
                                        ]);

    public function checkBoxRendererClickHandler(data:Object):void
    {
        Alert.show("click by " + data.description);
    }
    ]]>
</mx:Script>
<mx:DataGrid dataProvider="{ac}">
    <mx:columns>
        <mx:DataGridColumn headerText="index" dataField="index" />
        <mx:DataGridColumn headerText="description" dataField="description" />
        <mx:DataGridColumn headerText="radio" dataField="toggle">
            <mx:itemRenderer>
                <mx:Component>
                    <renderers:CheckBoxRenderer onClickFunction="{outerDocument.checkBoxRendererClickHandler}" />
                </mx:Component>
            </mx:itemRenderer>
        </mx:DataGridColumn>
    </mx:columns>
</mx:DataGrid>
</mx:Application>
[/code]

CheckBoxRenderer.as
[code as3]
package classes.controls.renderers
{
//-----------------------------------------------------------------------------
//
//  Import
//
//-----------------------------------------------------------------------------
import flash.events.MouseEvent;

import mx.core.IDataRenderer;
import mx.controls.CheckBox;
import mx.controls.dataGridClasses.DataGridListData;
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.IDropInListItemRenderer;
import mx.controls.listClasses.IListItemRenderer;
import mx.core.mx_internal;
import mx.events.FlexEvent;

use namespace mx_internal;

public class CheckBoxRenderer extends CheckBox
{
    //-----------------------------------------------------------------------------
    //
    //  Constructor
    //
    //-----------------------------------------------------------------------------
    /**
     *  Constructor.
     */
    public function CheckBoxRenderer()
    {
        super();
    }

    //-----------------------------------------------------------------------------
    //
    //  Variables
    //
    //-----------------------------------------------------------------------------
    /**
     *  @private
     *  데이터 변경 확인 플래그
     */
    private var dataChanged:Boolean = false;

    //-----------------------------------------------------------------------------
    //
    //  Properties
    //
    //-----------------------------------------------------------------------------
    //-------------------------------------
    //  onClickFunction
    //-------------------------------------
    /**
     *  @private
     */    
    private var _onClickFunction:Function;
    /**
     *  클릭시 실행할 콜백함수 속성
     */
    public function set onClickFunction(value:Function):void
    {
        _onClickFunction = value;
    }
    /**
     *  @private
     */    
    public function get onClickFunction():Function
    {
        return onClickFunction;
    }
    //-----------------------------------------------------------------------------
    //
    //  Override Properties
    //
    //-----------------------------------------------------------------------------
    override public function set data(value:Object):void
    {
        super.data = value;

        dataChanged = true;
        invalidateProperties();
    }

    //-----------------------------------------------------------------------------
    //
    //  Override Methods
    //
    //-----------------------------------------------------------------------------
    /**
     *  @private
     */
    override protected function createChildren():void
    {
        super.createChildren();
    }

    /**
     *  @private
     */
    override protected function commitProperties():void
    {
        super.commitProperties();

        if(dataChanged)
        {
            dataChanged = false;
            updateProperties();
        }
    }

    /**
     *  @private
     */
    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
    {
        super.updateDisplayList(unscaledWidth, unscaledHeight);

        currentIcon.x = (unscaledWidth - currentIcon.width) / 2;
    }

    //-----------------------------------------------------------------------------
    //
    //  Methods
    //
    //-----------------------------------------------------------------------------
    /**
     *  @private
     *  CheckBox의 속성을 변경
     */
    private function updateProperties():void
    {
        if(listData.label == "Y")
        {
            selected = true;
        }
        else
        {
            selected = false;
        }

        invalidateDisplayList();
    }

    //-----------------------------------------------------------------------------
    //
    //  Override EventHandler
    //
    //-----------------------------------------------------------------------------
    /**
     *  @private
     */
    override protected function clickHandler(event:MouseEvent):void
    {
        super.clickHandler(event);

        //data[DataGridListData(listData).dataField] = selected ? "Y" : "N";

        if(selected)
        {
            data[DataGridListData(listData).dataField] = "Y";
        }
        else
        {
            data[DataGridListData(listData).dataField] = "N";
        }

        if(_onClickFunction != null)
        {
            _onClickFunction(data);
        }
    }
}
}
[/code]

 

위와같이 코딩하게 되면 아래와 같은 산출물이 나오게 됩니다.

 

 

CheckBoxRenderer를 클릭해보세요. Alert창이 뜨는걸 볼 수 있지요.

그럼 2번 문제는 해결된것 같습니다. 그럼 1번 문제인 "Y", "N" 이외의 다른 문자열이 들어올땐 어떻게 할까요? 라는 문제는 방금 2번 문제를 해결한것과 같이 해결하면 될것 같습니다.

아래 처럼요.

 

[code as3]
package classes.controls.renderers
{
//-----------------------------------------------------------------------------
//
//  Import
//
//-----------------------------------------------------------------------------
import flash.events.MouseEvent;

import mx.core.IDataRenderer;
import mx.controls.CheckBox;
import mx.controls.dataGridClasses.DataGridListData;
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.IDropInListItemRenderer;
import mx.controls.listClasses.IListItemRenderer;
import mx.core.mx_internal;
import mx.events.FlexEvent;

use namespace mx_internal;

public class CheckBoxRenderer extends CheckBox
{
    //-----------------------------------------------------------------------------
    //
    //  Constructor
    //
    //-----------------------------------------------------------------------------
    /**
     *  Constructor.
     */
    public function CheckBoxRenderer()
    {
        super();
    }

    //-----------------------------------------------------------------------------
    //
    //  Variables
    //
    //-----------------------------------------------------------------------------
    /**
     *  @private
     *  데이터 변경 확인 플래그
     */
    private var dataChanged:Boolean = false;
    //-----------------------------------------------------------------------------
    //
    //  Properties
    //
    //-----------------------------------------------------------------------------
    //-------------------------------------
    //  onClickFunction
    //-------------------------------------
    /**
     *  @private
     */    
    private var _onClickFunction:Function;

    /**
     *  클릭시 실행할 콜백함수 속성
     */
    public function set onClickFunction(value:Function):void
    {
        _onClickFunction = value;
    }

    /**
     *  @private
     */    
    public function get onClickFunction():Function
    {
        return onClickFunction;
    }

    //-------------------------------------
    //  selectedFlag
    //-------------------------------------
    /**
     *  @private
     */    
    private var _selectedFlag:Array = ["Y", "N"];

    /**
     *  <p>true, false를 처리할 flag를 Array형태로 받아 처리.</p>
     *  <p>이때 selectedFlag의 length는 2를 초과할 수 없음.</p>
     *  @default    ["Y", "N"]
     */    
    public function set selectedFlag(value:Array):void
    {
        if(value.length > 2)
        {
            throw(new Error("selectedFlag:Array의 값은 두개를 초과할 수 없습니다."));
        }
        _selectedFlag = value;
    }

    /**
     *  @private
     */    
    public function get selectedFlag():Array
    {
        return _selectedFlag;
    }
    //-----------------------------------------------------------------------------
    //
    //  Override Properties
    //
    //-----------------------------------------------------------------------------
    override public function set data(value:Object):void
    {
        super.data = value;
        dataChanged = true;
        invalidateProperties();
    }
    //-----------------------------------------------------------------------------
    //
    //  Override Methods
    //
    //-----------------------------------------------------------------------------
    /**
     *  @private
     */
    override protected function createChildren():void
    {
        super.createChildren();
    }

    /**
     *  @private
     */
    override protected function commitProperties():void
    {
        super.commitProperties();

        if(dataChanged)
        {
            dataChanged = false;

            updateProperties();
        }
    }

    /**
     *  @private
     */
    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
    {
        super.updateDisplayList(unscaledWidth, unscaledHeight);

        currentIcon.x = (unscaledWidth - currentIcon.width) / 2;
    }

    //-----------------------------------------------------------------------------
    //
    //  Methods
    //
    //-----------------------------------------------------------------------------
    /**
     *  @private
     *  CheckBox의 속성을 변경
     */
    private function updateProperties():void
    {
        if(data[DataGridListData(listData).dataField] == _selectedFlag[0])
        {
            selected = true;
        }
        else
        {
            selected = false;
        }

        invalidateDisplayList();
    }

    //-----------------------------------------------------------------------------
    //
    //  Override EventHandler
    //
    //-----------------------------------------------------------------------------
    /**
     *  @private
     */
    override protected function clickHandler(event:MouseEvent):void
    {
        super.clickHandler(event);

        //data[DataGridListData(listData).dataField] = selected ? _selectedFlag[0] : _selectedFlag[1];

        if(selected)
        {
            data[DataGridListData(listData).dataField] = _selectedFlag[0];
        }
        else
        {
            data[DataGridListData(listData).dataField] = _selectedFlag[1];
        }

        if(_onClickFunction != null)
        {
            _onClickFunction(data);
        }
    }
}
}
[/code]

이렇게 수정하고 나면 눈으로 보기엔 아무 바뀐게 없어 보일지 모르겠지만 데이터가 "Y", "N"이 아니라 true나 false로 들어온다 하더라도 selectedFlag를 변경해주면 바로 적용할 수 있게 된다.

(163번째 줄 확인 꼭 하셔야합니다. label로 되어있던걸 data에서 바로 값을 뽑아서 비교하게끔 했어요. 이유는 true나 false같은 경우는 String이 아니기때문에 비교식 성립이 안되거든요.)

 

아래와 같이 Main.mxml 파일을 수정해보면 알 수 있다.

[code xml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:renderers="classes.controls.renderers.*">
<mx:Script>
    <![CDATA[
    import mx.collections.ArrayCollection;
    import mx.controls.Alert;

    [Bindable]
    private var ac:ArrayCollection = new ArrayCollection([
                               {index:1, description:"test1", toggle:true},
                               {index:2, description:"test2", toggle:false},
                               {index:3, description:"test3", toggle:false},
                               {index:4, description:"test4", toggle:true},
                               {index:5, description:"test5", toggle:false},
                               {index:6, description:"test6", toggle:false},
                               {index:7, description:"test7", toggle:true},
                               {index:8, description:"test8", toggle:false},
                               {index:9, description:"test9", toggle:false},
                               {index:10, description:"test10", toggle:false},
                               {index:11, description:"test11", toggle:false},
                               {index:12, description:"test12", toggle:false}
                               ]);

    public function checkBoxRendererClickHandler(data:Object):void
    {
        Alert.show("click by " + data.description);
    }
    ]]>
</mx:Script>
<mx:DataGrid dataProvider="{ac}">
    <mx:columns>
        <mx:DataGridColumn headerText="index" dataField="index" />
        <mx:DataGridColumn headerText="description" dataField="description" />
        <mx:DataGridColumn headerText="radio" dataField="toggle">
            <mx:itemRenderer>
                <mx:Component>
                    <renderers:CheckBoxRenderer
                        selectedFlag="{[true, false]}"
                        onClickFunction="{outerDocument.checkBoxRendererClickHandler}" />
                </mx:Component>
            </mx:itemRenderer>
        </mx:DataGridColumn>
    </mx:columns>
</mx:DataGrid>

</mx:Application>
[/code]

이제 대충 감이 오시나요?

Renderer에 대해서 감이 오셨다면 다행입니다.

하지만 "CheckBox"는 대충 알겠는데 "ComboBox"는? "ComboBoxRenderer"는 어떻게 만드나요? 라고 하신다면 1, 2, 3회에 걸쳐 Renderer에 대해 설명한 이유가 없어요. 다시 한번 훑어보시고 연구하시면 될거 같아요.

답은 스스로 만들어가는 것.

 

다음 시간엔... HeaderRenderer를 해볼까 하다가 좀 다른게 만져보고 싶어져서.. 기대하세요.

:
Posted by 라면스프