Archive for 6月, 2009
ArrayとArrayCollectionの違いについて、やっと腑に落ちたような気がした。
いろいろと書いてあり、マニュアルには
「ArrayCollection クラスは、ICollectionView または IList インターフェイスのメソッドとプロパティを使用して、アクセスおよび操作できるコレクションとして配列を公開するラッパークラスです。 ArrayCollection インスタンスに対する操作はデータソースを変更します。たとえば、ArrayCollection で removeItemAt() メソッドを使用した場合、元になる Array からアイテムが削除されます。 」
と書いてある。
この文面を見ても、理解できないところなどない。
でも、いまひとつ「なーるほど」と言えるほど、理解できない。
でも、前回 ICollectionViewを自作してみてわかった。
DataGridやTreeで表示する際には、表示されている部分だけを管理する必要性や、また、アクセスする方法も多々必要になる。
たとえば、GUIがなければremoveItemAtなどあまり必要がないメソッドだろう。
でも、DataGridで表示していれば、当然、選択した1行を削除などが必要になる。
このような操作ができるインターフェースが ICollecitonViewだ。
このようなデータモデルとして利用するときに、配列を扱えるようにしたものが、ArrayCollectionだと。
要するに、配列データをGUIと結ぶ上で必要な処理をするクラスという事です。
(もちろん、GUIと結ばなくても、イベント処理だけを使うなどもできますが・・・、それはICollecitonViewとは関係ありません。)
と、この説明を聞いていもよくわからないと思いますが、これらの関係がわかればFlexのデータモデルをかなり理解できたことになるのではないでしょうか?ぜひ、ソースを見てみることをお勧めします。
(といっても、まだ、IViewCursorとの関係がよく理解できていません。)
AdvancedDataGridが使えないフリーの方や、スタンダードの場合にはこのモデルしかつかわないともいえるので・・・
DataGridでテーブルの結果をデータとして表示したいときに、
stmt.text = "SELECT * FROM ......"; stmt.execute(); var result:SQLResult = stmt.getResult(); datagrid.dataProvider = new ArrayCollection(result.data);
のようにして、データを取得してArrayCollectionとして設定すればいい。
しかし、これではデータが大きかろうが、小さかろうがデータをすべて事前に作成する必要がある。
もし、これが20行しか表示されずに、そのままそのページを閉じられたとしてもだ。
これは何とも非効率だ。
そこで、必要なデータを、必要な時に作成するようにしたいと思っていろいろと調べていたが、
一番よいやり方は、DataProviderに設定できるICollectionViewのインターフェースをもったクラスを自作するのが一番だろうということになり、このクラスを自作することにした。
まだ、完全にはできていないものの、このクラスを自作しながらレポートしていく。
必要なサンプルクラスをさがす
dataProviderに設定するにはICollecitonViewのインターフェースをもったクラスだから、
この必要メソッドを作成していけば、いいわけだが、やみくもに作ってもしょうがない。
そこで、既存の実装でよいサンプルを探す。
やはり、このサンプルとして一番いいのは、ArrayCollecitonだろう。
データ自体がArrayなので、内容も把握しやすい。
そこでArrayCollecitonというクラスを見てみると、ほんの150行程度で実装が終わっている。
ようはやっていることは
(今回関係ある部分のみしか記述していません)
public class ArrayCollection extends ListCollectionView{
public function set source(s:Array):void{
list = new ArrayList(s);
}
}
というように、listプロパティに、IListの実装としてArrayListを設定しているListCollectionViewということがいえる。
したがって、今回自作するクラスもこのような形として実装すればなんとかなりそうだ。
実装するクラス
前述の通り、今回実装するクラスは
- TableCollecitonView
- TableList
とする。
ちょうど、TableCollecitonViewがArrayCollectionを参考にし、TableListがArrayListを参考に実装すればよいというわけだ。
では、これらの実装を次回からしていくことにする。
参考までに、ArrayListというクラス、publicなクラスだが、@privateとなっていてドキュメントからは表示されないようになっている。
Flexにはnamespaceというキーワードがある。
これは簡単にいえば、メソッドやプロパティのアクセス制御のためだと言ってしまってもいい。
どのようなときに使うかといえば、簡単に言ってしまえば内部事情を分かっている人だけに公開したいメソッドやプロパティを作りたい。
というときだろう。逆にいえば、外部に対しては見せたくないが、いろいろなパッケージで自由に使いたいときだろう。
たとえば、mx_internal。
flex framework を作っているAdobe向けの名前空間。flexのコンポーネントを改良しようかなと思うと必ずこのキーワードのあいます。
使い方は以下のようなたとえば、私の場合にはファイル(/com/coltware/fxmail_internal.as)を作成し、
package com.coltware
{
public namespace fxmail_internal = "http://www.coltware.com/2009/fxmail/internal";
}
次に、この名前空間に関数を定義するには
fxmail_internal function parseEnd():void{
}
のように、頭につければよい。publicや、protectedとかは一緒に使えません。
そして、使い方(その関数の呼び方)。
これはいろいろありますが、
import com.coltware.fxmail_internal; use namespace fxmail_internal;
と宣言してしまえば、使えます。後はふつうnamespaceを使っていない時と同様です。
今まで、どうせ自分ひとりのソースだからpublicでいいやとおもっていましたが、asdocでpublicは表示されるのはおかしいから変えようかなと思い、namespaceを使いましたが・・
ドキュメントは@privateと書けば出ませんでした・・・
Arrayオブジェクトのコピーをしようとするときに、Array.copy() とかって感じのメソッドがあるかと思ったら,
[ないので、中に納めているデータが小さければ単純にfor文でまわしてコピーしてしまっていた。
そしたら、
array.concat();
のように引数なしで呼べばいいですね。
array.splice()
も同様にできるようですが、ちょっとこれは、トリッキーすぎますよね。
ソースを見ても、何がいいたいのか?わからないですよね。
まあ、concatは言われてみれば、指定された配列をマージして新しい配列で返すというようなことが書いてあるので・・・・。
これ、ArrayListというArrayCollectionのソースを見ていたら、なんでこんなことをするのかな?とちょっと目にとまったので気がつきました
そしたら、ちゃんとマニュアル(ヘルプ)にも、「配列のクローンの作成」っていう題で記述があるじゃないですか・・・。
でも、書くまでそこで「んっ」って思う事がわかっているのならば、ぜひとも、その前に用意しておいてほしいですよね。
別にメソッドのalias でもいいですから。
前回、asdocを実行しようとしてAntをFlex Builderにインストールしてみた。
ところが、asdocのタスクはないではないみたいなのです。
まあ、仕方がないので結局Antから外部コマンドという形で実行できるようにbuild.xmlを作ってみたのでよかったら使ってみてください。
< ?xml version="1.0" encoding="UTF-8" ?>
<project name="fxmail" basedir="..">
<!-- FLEX SDKの設定 -->
<!-- ******* 以下 環境に合わせて書き直すこと ************* -->
<!--
SDKの場所を指定
(自動でとれないかな)
-->
<property name="FLEX_SDK" value="C:\Program Files\Adobe\Flex Builder 3\sdks\3.2.0" />
<!--
注意)
Flash Verison 10 の場合にはflex-configの自作が必要
ただし、中で呼んでいるライブラリが相対パスになっているみたいで、全部移すのが面倒なので同じ階層に作成してしまう。
-->
<!-- <property name="load-config" value="-load-config '${FLEX_SDK}/frameworks/flex-config_p10.xml'" /> -->
<property name="load-config" value="-load-config '${FLEX_SDK}/frameworks/flex-config.xml'" />
<!-- ソースのディレクトリ -->
<property name="SRC_PATH" value="${basedir}/src" />
<property name="FLEX_ANT" value="${FLEX_SDK}/ant/lib" />
<property name="FLEX_BIN" value="${FLEX_SDK}/bin" />
<!--
**********************************************************************
ASDOC のための設定
**********************************************************************
-->
<!-- addocの出力フォルダ -->
<property name="ASDOC_DIR" value="${basedir}/dist/asdoc" />
<!--
*********************************************************************
ここからターゲット処理
*********************************************************************
-->
<target name="asdoc">
<exec executable="${FLEX_BIN}/asdoc.exe">
<arg line="-source-path ${SRC_PATH} -doc-sources ${SRC_PATH} -output ${ASDOC_DIR} ${load-config}"/>
<env key="JAVA_HOME" value="${java.home}"/>
</exec>
</target>
</project>
ちなみに、Windows用になっていますので、それ以外の人は環境に合わせて読み替えてください。
(とくに、asdoc.exeなんかはほかのOSでそうなのかとは知りません。)
あとは、JAVA_HOMEの環境変数が設定されていないとエラーメッセージが表示されたので環境変数を設定しました。(${java.home})
また、私のディレクトリ構造は
Project HOME
|–>src (ソースフォルダ)
|–>dist
|–> asdoc ( この下にドキュメントを作成)
|–> build.xml (ここがbuild.xmlの位置です。)

