Flex AdvancedDataGridでItemRenderer(TextInput)をタブ移動しながら金額をカンマ区切りにするサンプル
Flex AdvancedDataGridで、ItemRenderer(TextInput)をタブ移動しながら金額をカンマ区切りにするサンプルです。
FLEX(AIR)で、一覧表示を作る場合、DataGrid
を利用しますね。しかし、ヘッダ部分をグループ化して表示したい ( Excelでいうセル結合した状態のようなもの ) などのニーズがあった場合、DataGrid
ではなく、AdvancedDataGrid
を利用します。
今回はこの AdvancedDataGrid
とItemrenderer
を使って「タブ移動しながら数値の入力を行い、カンマ区切り表示するサンプル」を紹介します。
目次
完成図
完成図はこんな感じになります。
ソース
それでは実際のソースを見ながら解説してきます。
NumericTextInputRenderer.as
数値入力用の ItemRenderer
です。
package
{
import flash.events.Event;
import flash.events.FocusEvent;
import mx.containers.HBox;
import mx.controls.AdvancedDataGrid;
import mx.controls.dataGridClasses.DataGridListData;
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.IDropInListItemRenderer;
import mx.controls.listClasses.IListItemRenderer;
import mx.managers.IFocusManager;
import mx.managers.IFocusManagerComponent;
/**
* 数値入力レンダラー
*/
public class NumericTextInputRenderer extends HBox implements IListItemRenderer, IDropInListItemRenderer, IFocusManagerComponent
{
/**
* コンストラクタ
*/
public function NumericTextInputRenderer()
{
super();
}
/**
* NumericTextInput
*/
private var textInput:NumericTextInput = null;
/**
* listData
*/
private var _listData:BaseListData;
[Bindable("dataChange")]
[Inspectable(environment="none")]
public function get listData():BaseListData {
return this._listData;
}
public function set listData(value:BaseListData):void {
this._listData = value;
}
/**
* TextInputのID
*/
private var _tid:String = "";
public function get tid():String {
return this._tid;
}
public function set tid(tid:String):void {
this._tid = tid;
}
/**
* @private
* Create components that are children of this Container.
*/
override protected function createChildren():void
{
super.createChildren();
this.textInput = new NumericTextInput();
this.textInput.width = 100;
this.textInput.maxChars = 16;
this.textInput.imeMode = "ALPHANUMERIC_HALF";
this.textInput.precision = 0; // 小数点以下の表示桁数
this.id = _tid;
this.textInput.addEventListener(FocusEvent.FOCUS_OUT, function(event:FocusEvent):void {
if ( event.currentTarget.text == "" )
return;
var dgOwner:AdvancedDataGrid = event.currentTarget.owner.owner as AdvancedDataGrid;
var idx:int = dgOwner.selectedIndex;
data[DataGridListData(_listData).dataField] = event.currentTarget.text;
dgOwner.dataProvider[idx][DataGridListData(_listData).dataField] = event.currentTarget.text;
dgOwner.validateNow();
dgOwner.dispatchEvent(event);
});
addChild(this.textInput);
}
/**
* 表示処理
*/
override protected function commitProperties():void
{
super.commitProperties();
if ( data != null )
this.textInput.text = data[DataGridListData(_listData).dataField];
}
/**
* フォーカスセット
*/
override public function setFocus():void
{
var fm:IFocusManager = this.focusManager;
if (IFocusManagerComponent(this.textInput) != fm.getFocus())
fm.setFocus(IFocusManagerComponent(this.textInput));
}
}
}
カスタムコンポーネントで、TAB キー押下時にフォーカスを移動するためには、カスタムコンテナに IFocusManagerComponent
インタフェースを実装します。
createChildren
createChildren
メソッドをオーバーライドし、子コンポーネントである、NumericTextInput
を生成します。NumericTextInput
については「Flex TextInputで数値のみ入力できてカンマ区切りにするサンプル」を参考にしてください。
フォーカスアウト時に、入力データをリストデータに書き換えるために、FOCUS_OUT イベントを追加しています。
commitProperties
commitProperties
メソッドをオーバーライドします。リストデータに値が存在する場合は、TextInput
に表示します。
setFocus
IFocusManager
を利用し、フォーカスセットをおこないます。
CharacterTextInputRenderer.as
文字列入力用の ItemRenderer
です。
package
{
import mx.containers.HBox;
import mx.controls.dataGridClasses.DataGridListData;
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.IDropInListItemRenderer;
import mx.controls.listClasses.IListItemRenderer;
import mx.managers.IFocusManager;
import mx.managers.IFocusManagerComponent;
/**
* 文字列入力レンダラー
*/
public class CharacterTextInputRenderer extends HBox implements IListItemRenderer, IDropInListItemRenderer, IFocusManagerComponent
{
/**
* コンストラクタ
*/
public function CharacterTextInputRenderer()
{
super();
}
private var textInput:CharacterTextInput = null;
/**
* listData
*/
private var _listData:BaseListData;
[Bindable("dataChange")]
[Inspectable(environment="none")]
public function get listData():BaseListData
{
return this._listData;
}
public function set listData(value:BaseListData):void
{
this._listData = value;
}
/**
* TextInputのID
*/
private var _tid:String = "";
public function get tid():String {
return this._tid;
}
public function set tid(tid:String):void {
this._tid = tid;
}
/**
* @private
* Create components that are children of this Container.
*/
override protected function createChildren():void
{
super.createChildren();
this.textInput = new CharacterTextInput();
this.textInput.width = 150;
this.textInput.maxChars = 80;
addChild(this.textInput);
}
/**
* 表示処理
*/
override protected function commitProperties():void
{
super.commitProperties();
if ( data != null )
this.textInput.text = data[DataGridListData(_listData).dataField];
}
/**
* フォーカスセット
*/
override public function setFocus():void
{
var fm:IFocusManager = this.focusManager;
if (IFocusManagerComponent(this.textInput) != fm.getFocus())
fm.setFocus(IFocusManagerComponent(this.textInput));
}
}
}
NumericTextInputRenderer.as とやっていることは同じですので、説明は割愛します。
子コンポーネントとして利用している CharacterTextInput
については「Flex クリックやフォーカスイン時にTextInputのテキストを選択状態にするサンプル」を参考にしてください。
AdvancedDataGridInputTest.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="544"
height="312"
xmlns:local="*"
initialize="onInit()">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.AdvancedDataGridEvent;
import mx.events.AdvancedDataGridEventReason;
import mx.formatters.NumberFormatter;
import mx.utils.ObjectProxy;
/**
* 初期化
*/
protected function onInit():void {
StyleManager.getStyleManager(null).loadStyleDeclarations("css/blue.swf");
companyName.setFocus();
}
[Bindable]
private var arr:Array = [
{ no: "1", debitAccountsTitle: "現金", debitPrice: "20,000", creditAccountsTitle: "当座預金", creditPrice: "20,000" },
{ no: "2", debitAccountsTitle: "受取手形", debitPrice: "30,000", creditAccountsTitle: "売掛金", creditPrice: "30,000" },
{ no: "3", debitAccountsTitle: "仮払金", debitPrice: "70,000", creditAccountsTitle: "現金", creditPrice: "70,000" },
{ no: "4", debitAccountsTitle: "仕入", debitPrice: "100,000", creditAccountsTitle: "支払手形", creditPrice: "100,000" },
{ no: "5", debitAccountsTitle: "売掛金", debitPrice: "200,000", creditAccountsTitle: "売上高", creditPrice: "200,000" },
];
private function summary():void {
errorMsg.text = "";
var debitTotal:Number = 0;
var creditTotal:Number = 0;
for ( var i:int = 0; i < arr.length; i++ ) {
debitTotal += Number(dataList.dataProvider[i].debitPrice.replace(new RegExp(",", "g"), ""));
creditTotal += Number(dataList.dataProvider[i].creditPrice.replace(new RegExp(",", "g"), ""));
}
debitPriceTotal.text = format(debitTotal.toString());
creditPriceTotal.text = format(creditTotal.toString());
if ( debitPriceTotal.text != creditPriceTotal.text )
errorMsg.text = "借方と貸方の合計金額が一致しません"
}
private function format(text:String):String {
var nf:NumberFormatter = new NumberFormatter();
nf.useThousandsSeparator = true;
nf.useNegativeSign = true;
return nf.format(text);
}
]]>
</fx:Script>
<fx:Declarations>
<fx:Component id="debitAccountsTitleRenderer">
<local:CharacterTextInputRenderer horizontalGap="0" borderStyle="none" color="0x000000" horizontalScrollPolicy="off" tid="debitAccountsTitle" />
</fx:Component>
<fx:Component id="debitPriceRenderer">
<local:NumericTextInputRenderer horizontalGap="0" borderStyle="none" color="0x000000" horizontalScrollPolicy="off" textAlign="right" tid="debitPrice" />
</fx:Component>
<fx:Component id="creditAccountsTitleRenderer">
<local:CharacterTextInputRenderer horizontalGap="0" borderStyle="none" color="0x000000" horizontalScrollPolicy="off" tid="creditAccountsTitle" />
</fx:Component>
<fx:Component id="creditPriceRenderer">
<local:NumericTextInputRenderer horizontalGap="0" borderStyle="none" color="0x000000" horizontalScrollPolicy="off" textAlign="right" tid="creditPrice" />
</fx:Component>
</fx:Declarations>
<mx:VBox width="100%" >
<mx:HBox width="100%">
<mx:FormItem width="100%" label="会社名">
<local:CharacterTextInput id="companyName" text="saka-en." width="100%" maxChars="40" />
</mx:FormItem>
</mx:HBox>
<mx:AdvancedDataGrid id="dataList" width="100%" initialize="dataList.dataProvider=arr" rowCount="7" allowMultipleSelection="true" editable="true" itemEditEnd="event.reason = AdvancedDataGridEventReason.CANCELLED" >
<mx:groupedColumns>
<mx:AdvancedDataGridColumn dataField="no" width="35" headerText="No." textAlign="right" editable="false"/>
<mx:AdvancedDataGridColumnGroup headerText="借方">
<mx:AdvancedDataGridColumn dataField="debitAccountsTitle" width="150" headerText="勘定科目" itemRenderer="{debitAccountsTitleRenderer}" rendererIsEditor="true" editable="true" />
<mx:AdvancedDataGridColumn dataField="debitPrice" width="100" headerText="金額" itemRenderer="{debitPriceRenderer}" rendererIsEditor="true" editable="true" />
</mx:AdvancedDataGridColumnGroup>
<mx:AdvancedDataGridColumnGroup headerText="貸方">
<mx:AdvancedDataGridColumn dataField="creditAccountsTitle" width="150" headerText="勘定科目" itemRenderer="{creditAccountsTitleRenderer}" rendererIsEditor="true" editable="true" />
<mx:AdvancedDataGridColumn dataField="creditPrice" width="100" headerText="金額" itemRenderer="{creditPriceRenderer}" rendererIsEditor="true" editable="true" />
</mx:AdvancedDataGridColumnGroup>
</mx:groupedColumns>
</mx:AdvancedDataGrid>
<mx:HBox width="100%">
<mx:FormItem width="100%" label="借方計">
<mx:HBox width="100%" styleName="total">
<mx:Spacer width="100%" />
<mx:Text id="debitPriceTotal" text="0" />
</mx:HBox>
</mx:FormItem>
<mx:FormItem width="100%" label="貸方計">
<mx:HBox width="100%" styleName="total">
<mx:Spacer width="100%" />
<mx:Text id="creditPriceTotal" text="0" />
</mx:HBox>
</mx:FormItem>
</mx:HBox>
<mx:HBox width="100%">
<mx:Button id="sum" label="総額表示" click="summary()" />
<mx:HBox width="100%" styleName="errorMsgBox">
<mx:Text id="errorMsg" height="20" />
</mx:HBox>
</mx:HBox>
</mx:VBox>
</s:Application>
サンプルソースのダウンロード
サンプルソースは、こちら からダウンロードできます。
おつかれさまでした。