Archive for 2009/6/9
DBのデータを利用してtreeを作成するにはどうやったらいいのかなーと頭にとどめながらふと、Flex SDKの中でTreeでfindしてみたら、
FilesystemTreeというものがあり、そこで自分でTreeに提供するデータを自作するためのいいサンプルがあった。
私は今まで、DataProviderを自作すればいいのかなと思って、探していたが、DataDescriptorというのを自作すればいいらしい。
ようするに、DataProviderはデータそのものであり、DataDescriptorはデータの表記方法という感じで分かれているという感じであろうか?
(ちょっとちがうかな???)
というわけで、DataDescriptorを自作してDBのデータからTreeを作成する。
ちなみにDB(テーブル)はこのようになっている。
var sql:String = "CREATE TABLE IF NOT EXISTS tree(" +
"uid INTEGER PRIMARY KEY AUTOINCREMENT," +
"pid INTEGER NOT NULL," +
"branch BOOL NOT NULL," +
"title VARCHAR(100) NOT NULL" +
")";
これはあらかじめ作成しておいてください。
また、データもあらかじめ作成しておいてください。
insert into tree(pid,branch,title) values(0,1,'title1'); insert into tree(pid,branch,title) values(0,1,'title2'); insert into tree(pid,branch,title) values(0,1,'title3'); insert into tree(pid,branch,title) values(1,0,'title1-1'); insert into tree(pid,branch,title) values(1,0,'title1-2'); insert into tree(pid,branch,title) values(1,0,'title1-3');
のように作成してもらえればと思います。
branchフィールドは、単純にbranchか?どうか?ということを示すフィールドで、
pidは、親IDなので、親となるuidの値をいれてもらえればと思います。
さて、これで表示するためのデータが作成できました。
これを表示するための、DataDescriptorを自作していきます。
FilesystemTreeによれば、DataDescriptorはFileSystemTreeDataDescriptorというクラスで、
DefaultDataDescriptorを継承しています。
これとまったく同じようにして作成します。
このクラスでoverride しているのは3つのメソッドのみです。
- isBranch
- hasChildren
- getChildren
の3つです。
これらを実装したソースを以下に示します。
package com.coltware.cise.db
{
import flash.data.SQLConnection;
import flash.data.SQLResult;
import flash.data.SQLStatement;
import mx.collections.ArrayCollection;
import mx.collections.ICollectionView;
import mx.controls.treeClasses.DefaultDataDescriptor;
public class DBTreeDescriptor extends DefaultDataDescriptor
{
private var _conn:SQLConnection;
/**
* テーブル名
*/
public var tableName:String = "tree";
public var pkeyField:String = "uid";
public var parentField:String = "pid";
public var branchField:String = "branch";
public function DBTreeDescriptor(){
super();
}
public function set sqlConnection(conn:SQLConnection):void{
this._conn = conn;
}
/**
* データ表示のためのTreeのDataProviderに設定するデータを取得する
*/
public function getRootCollection():ICollectionView{
var root:Object = new Object();
root[this.pkeyField] = 0;
root[this.branchField] = true;
root[this.parentField] = -1;
return this.getChildren(root);
}
/* ************** 以下3つのoverrideメソッドは呼ばれる順番に記述 *********** */
/**
* branch(フォルダ)かどうか?フォルダならば、xxxChildrenが開かれたときに呼ばれる
*/
override public function isBranch(node:Object, model:Object=null):Boolean{
return node[this.branchField];
}
/**
* 子ノードを持っているか?持っていれば、 getChildren()メソッドが呼ばれる
*/
override public function hasChildren(node:Object, model:Object=null):Boolean{
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = this._conn;
stmt.text = "SELECT count(*) as cnt FROM " + this.tableName + " WHERE " + this.parentField + " = :KEY";
stmt.parameters[":KEY"] = node[this.pkeyField];
stmt.execute();
var ret:Object = this.getRow(stmt);
if(ret != null && ret.cnt> 0 ){
return true;
}
return false;
}
/**
* 子を返す。返されたノードの isBranchメソッドによるチェックで再帰的に子ノードが展開される
*/
override public function getChildren(node:Object, model:Object=null):ICollectionView{
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = this._conn;
stmt.text = "SELECT * FROM " + this.tableName + " WHERE " + this.parentField + " = :KEY";
stmt.parameters[":KEY"] = node[this.pkeyField];
stmt.execute();
var result:SQLResult = stmt.getResult();
if(result != null && result.data != null){
if(result.data.length> 0 ){
return new ArrayCollection(result.data);
}
}
return new ArrayCollection();
}
private function getRow(stmt:SQLStatement):Object{
var result:SQLResult = stmt.getResult();
if(result != null && result.data != null){
if(result.data.length> 0 ){
return result.data[0];
}
}
return null;
}
}
}
一応、テーブル名やフィールド名は変えらるようにしていますが、データ構造などは変更できません。
また、利用するには、
var conn:SQLConnection = new SQLConnection();
var file:File = File.applicationStorageDirectory.resolvePath("tree.sqlite");
conn.open(file);
var descriptor:DBTreeDescriptor = new DBTreeDescriptor();
descriptor.sqlConnection = conn;
dbtree.dataDescriptor = descriptor;
/* DataProviderに初めのArrayCollectionだけは取得して設定する */
dbtree.dataProvider = descriptor.getRootCollection();
dbtree.labelField = "title";
のような感じです。
これができれば結構Treeが使いやすくなるのではないでしょうか?
今まで、データをすべて作成してchildrenプロパティに入れていましたが、その苦労をしていたのが無駄になってしまいました。

