2008/12/20

labelFunctionかItemRendererか。それとあとFormatter (5)

前回の続き。

前回までで「動的に1000単位とかに切り替えられる仕組み」は完結。
ただ、「いちいちそれ用に作ってあげないといけない」という課題があった。
「それ用に」と言っているのは、たとえば同じような話をListコンポーネントのlabelFunctionにやってあげたりとか、あるいはLabelコンポーネントのtextプロパティにこれを使おうとしても、format関数のシグネチャがDataGrid専用になってるので使い回しが利かない、ということ。

というわけで、これを解決すべく、前回までのVariableCurrencyFormatterのformat関数のシグネチャを変えて対応できるようにしてみようかと。

このVariableCurrencyFormatterの使われそうなところを考えてみると、上記のとおりDataGridとListとLabelがあるので、それぞれどういう感じか考えてみる。

まず、DataGridは今までのとおり、

public function format(item:Object, column:DataGridColumn):String

のシグネチャでOK。

Listは、

public function format(item:Object):String

なんだけど、item はその行が表示対象とするオブジェト、まぁ大抵はいわゆるDTOってやつが来るんだけど、どのプロパティを表示するかを渡してあげないとまずい。
ListコンポーネントにはlabelFieldっていうのがあって、Listの場合はそれで指定することになるので、同じように外部から与えられるようにすればいいでしょう。

ていうか、listっていうListコンポーネントがあったとしたら、

<formatters:VariableCurrencyFormatter labelField="{list.labelField}" />

ってなっているのがわかりやすい。

Labelの場合、使い方としては、

<mx:Label text="{formatter.format(hoge)}" />

という感じだろうから、引数として1個のObjectを取ってStringを返すので十分。


シグネチャが違うのだけれど、ActionScriptだと引数にデフォルト値をしておけば関数のオーバーロードみたいなのができるので、これを使えばできそう。

というわけで、

[Bindable(event="formatChanged")]
public function format(item:Object, column:DataGridColumn = null):String
{
var dat:Object = item;

if (column != null && item.hasOwnProperty(column.dataField))
{
dat = item[column.dataField];
}
else if (labelField != null && item.hasOwnProperty(labelField))
{
dat = item[labelField];
}

var curFormatter:CurrencyFormatter = new CurrencyFormatter();
return curFormatter.format(Number(dat) / unit);
}

private var _labelField:String;

[Bindable]
public function get labelField():String { return _labelField; }
public function set labelField(value:String):void
{
if (_labelField != value)
{
_labelField = value;
dispatchEvent(new Event("formatChanged"));
}
}


と書いてみた。

これでDataGrid、List(ついでにlabelFieldが動的に変わっても対応可能)、Labelのそれぞれで同じ感じに使えるようにできた。