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プロパティに入れていましたが、その苦労をしていたのが無駄になってしまいました。

お仕事のご依頼・相談を承ります
この記事に関連するお仕事のご依頼やご相談をお待ちしております。 詳しくは、こちら

Leave a Reply

お仕事のご依頼・相談
この記事に関連するお仕事のご依頼やご相談をお待ちしております。 詳しくは、こちら
ソフトウェア&ライブラリ




ライブラリ
airxmail(en)
AIR版メール送受信ライブラリ
airxzip
AIR版ZIP圧縮・解凍ライブラリ
執筆書籍
本、雑誌等

WEB記事:CodeZine
執筆記事はこちら
カレンダー
2009年6月
« 5月   7月 »
1234567
891011121314
15161718192021
22232425262728
2930  

カスタム検索
RSS
Add to Google < !–adsense–>
アーカイブ
カテゴリ
にほんブログ村 IT技術ブログへ