ツリー


木構造の表示

コンピュータの世界では、木構造の情報が頻繁に用いられます
なぜならば、情報を管理する最も基本的な形が木構造だからですが
グラフィカルな環境では、やはりこの木構造を表示する方法が重要になります

最も一般的な、直観的な表示方法はツリーを使ったものです
ツリーは javax.swing.JTree コンポーネントで実装されています
java.lang.Object
  |
  +--java.awt.Component
        |
        +--java.awt.Container
              |
              +--javax.swing.JComponent
                    |
                    +--javax.swing.JTree

public class JTree extends JComponent
	implements Scrollable, Accessible
このクラスは次のようなコンストラクタを公開しています

public JTree()
public JTree(Object[] value)
public JTree(Vector value)
public JTree(Hashtable value)
public JTree(TreeNode root)
public JTree(TreeNode root , boolean asksAllowsChildren)
public JTree(TreeModel newModel)

value には、ツリーの各ノードを表す配列や Vector などを指定します
Hashtable 以外の場合、子ノードを持たないノードとして用いられますが
Hashtable は内部に Hashtable を抱合する場合、子ノードを定義することができます

root には指定したルートとなるのノードを指定します
asksAllowsChildren false の場合、子を持たないすべてのノードがリーフ
true の場合、子を許可しないノードだけがリーフであることを表します

newModel は、ツリーのデータモデルを指定します
TreeNode と TreeModel については後で詳しく解説します
まずは、最も簡単なツリーの作り方を見てみましょう
import java.util.*;
import java.awt.*;
import javax.swing.*;

public class Test extends JApplet {
	public void init() {
		String str1[] = {
			"涼宮 遙" , "速瀬 水月" , "涼宮 茜" ,
			"大空寺 あゆ" , "玉野 まゆ"
		};
		String str2[] = {
			"鑑 純夏" , "御剣 冥夜" , "榊 千鶴" ,
			"彩峰 慧" , "珠瀬 壬姫"
		};

		Hashtable node = new Hashtable();
		node.put("The forever that you wish" , str1);
		node.put("MUV-LUV" , str2);

		JTree tree = new JTree(node);
		getContentPane().add(new JScrollPane(tree));
	}
}


このプログラムは、ハッシュテーブルを使ってツリーをモデル化しています
これを JTree() コンストラクタに渡してツリーを実現します

ツリーのノードは、javax.swing.tree.TreeNode インターフェイスで表されます
さらに、ノードを追加したり削除したりする動的なノードの建設には
TreeNode を継承した javax.swing.tree.MutableTreeNode を使います

public interface TreeNode
public interface MutableTreeNode extends TreeNode

これらを実体化することで独自のノードを建設することができますが
この場では、javax.swing.tree.DefaultMutableTreeNode を使いましょう
多くのケースでは、このクラスを使うだけで十分だと思われます
public class DefaultMutableTreeNode extends Object
	implements Cloneable, MutableTreeNode, Serializable
このクラスのコンストラクタは次のようなものがあります

public DefaultMutableTreeNode()
public DefaultMutableTreeNode(Object userObject)
public DefaultMutableTreeNode(Object userObject , boolean allowsChildren)

userObject には、ノードデータとなる Object を
allowChildren には子ノードを持つことを許可するかどうかを示すブーリアンを指定します
ノードの表示には Object.toString() が利用されます

ノードは、親と子の情報を保有します
子ノードの追加は DefaultMutableTreeNode.add() メソッドで行い
削除には DefaultMutableTreeNode.remove() メソッドを使います

public void add(MutableTreeNode newChild)
public void remove(int childIndex)
public void remove(MutableTreeNode aChild)

newChild には追加する子ノードを指定します
追加された newChild は設定されている親ノードが変更されます
childIndex には削除するノードの位置を先頭から順に表すインデックスを指定します
aChild は、削除するノードを指定します
import java.util.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;

public class Test extends JApplet {
	public void init() {
		MutableTreeNode node[] = {
			new DefaultMutableTreeNode("涼宮 遙") ,
			new DefaultMutableTreeNode("速瀬 水月") ,
			new DefaultMutableTreeNode("涼宮 茜") ,
			new DefaultMutableTreeNode("大空寺 あゆ") ,
			new DefaultMutableTreeNode("玉野 まゆ")
		};
		DefaultMutableTreeNode root = 
			new DefaultMutableTreeNode("The forever that you wish");
		for(int i = 0 ; i < node.length ;i++) root.add(node[i]);

		JTree tree = new JTree(root);
		getContentPane().add(new JScrollPane(tree));
	}
}


このプログラムは、ルートノード(根)となる root と
root の子になる node 配列を作成して、これをツリーで表示しています


ツリーのイベント

ツリーの展開や選択を処理するにはリスナを登録しなければなりません
選択リスナは JTree.addTreeSelectionListener() で登録し
JTree.removeTreeSelectionListener() で削除することができます

public void addTreeSelectionListener(TreeSelectionListener tsl)
public void removeTreeSelectionListener(TreeSelectionListener tsl)

tsl には、登録、または削除するツリー選択リスナを指定します
リスナは javax.swing.event.TreeSelectionListener インターフェイスです

public interface TreeSelectionListener extends EventListener

このインターフェイスには、選択された時に呼び出されるメソッド
TreeSelectionListener.valueChanged() が宣言されています

public void valueChanged(TreeSelectionEvent e)

e には、イベント情報を受ける TreeSelectionEvent を指定します
これは javax.swing.event.TreeSelectionEvent クラスを使います
このクラスは、選択されたノードまでのパス情報を格納しています
java.lang.Object
  |
  +--java.util.EventObject
        |
        +--javax.swing.event.TreeSelectionEvent

public class TreeSelectionEvent extends EventObject
このクラスのコンストラクタを呼び出すことはほとんどないと思われるので省略します
このクラスをインスタンスかするのは、ほとんどがイベント発生元のクラスです
選択された最初のパスは TreeSelectionEvent.getPath() メソッドで
複数選択のパスは TreeSelectionEvent.getPaths() で得られます

public TreePath getPath()
public TreePath[] getPaths()

単一項目の選択であれば getPath() メソッドで十分ですが
複数選択のツリーで全ての選択を得る場合は getPaths() を使うことになります

これらのメソッドが返す javax.swing.tree.TreePath クラスのオブジェクトは
選択されてるノードまでの道筋を含んだ木構造上の位置を示すための情報を提供します

public class TreePath extends Object implements Serializable

このクラスは、次のようなコンストラクタを公開しています
通常は、このクラスのインスタンスを作成するのは Swing クラスです
このほかにも protected コンストラクタが定義されていますが、省略します

public TreePath(Object singlePath)
public TreePath(Object[] path)

singlePath にはノードへのパスを表すオブジェクトを
path にはノードへのパスを表すオブジェクトの配列を指定します
このクラスが保有するパスは TreePath.getPath() が返します

public Object[] getPath()

このメソッドは、ツリーのルート要素から順に並べられたパスを表す Object を返します
toString() メソッドを呼び出せば、ノード名を取得することができるでしょう
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;

public class Test extends JApplet implements TreeSelectionListener {
	public void init() {
		MutableTreeNode leaf1[] = {
			new DefaultMutableTreeNode("大空寺 あゆ") ,
			new DefaultMutableTreeNode("玉野 まゆ")
		};
		MutableTreeNode leaf2[] = {
			new DefaultMutableTreeNode("彩峰 慧") ,
			new DefaultMutableTreeNode("榊 千鶴")
		};
		DefaultMutableTreeNode node1 =
			new DefaultMutableTreeNode("The forever that you wish");
		DefaultMutableTreeNode node2 =
			new DefaultMutableTreeNode("MUV-LUV");
		for(int i = 0 ; i < leaf1.length ;i++) node1.add(leaf1[i]);
		for(int i = 0 ; i < leaf2.length ;i++) node2.add(leaf2[i]);

		DefaultMutableTreeNode root = 
			new DefaultMutableTreeNode("Age");
		root.add(node1);
		root.add(node2);

		JTree tree = new JTree(root);
		tree.addTreeSelectionListener(this);

		getContentPane().add(new JScrollPane(tree));
	}
	public void valueChanged(TreeSelectionEvent e) {
		JOptionPane.showMessageDialog(
			this , e.getPath().getPath() , "Forget me Not" , 
			JOptionPane.INFORMATION_MESSAGE
		);

	}
}


このプログラムは、ノードを選択するとメッセージダイアログを表示し
選択されたノードまでのパスを表示します

ノードの展開と収縮を処理するには、TreeExpansionListener リスナを登録します
これは JTree.addTreeExpansionListener() メソッドで登録し
JTree.removeTreeExpansionListener() で削除することができます

public void addTreeExpansionListener(TreeExpansionListener tel)
public void removeTreeExpansionListener(TreeExpansionListener tel)

tel には、登録、または削除する TreeExpansionListener を指定します
リスナは javax.swing.event.TreeExpansionListener を実装します

public interface TreeExpansionListener extends EventListener

このインターフェイスは、2つのメソッドを宣言しています
展開時に TreeExpansionListener.treeExpanded() メソッドが
収納時に TreeExpansionListener.treeCollapsed() が呼び出されます

public void treeExpanded(TreeExpansionEvent event)
public void treeCollapsed(TreeExpansionEvent event)

event には展開または収納を行ったパスに関する情報を指定します
javax.swing.event.TreeExpansionEvent クラスは
展開や収納が行われたノードのパスを保有するイベントクラスです

public class TreeExpansionEvent extends EventObject

このクラスは、対象ノードを返す TreeExpansionEvent.getPath() を提供します

public TreePath getPath()

このメソッドは、展開または収納されたパスを返します
展開や収納が同時に多発することはありません
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;

public class Test extends JApplet implements TreeExpansionListener {
	Label label = new Label("展開されたノード");
	public void init() {
		MutableTreeNode leaf1[] = {
			new DefaultMutableTreeNode("大空寺 あゆ") ,
			new DefaultMutableTreeNode("玉野 まゆ")
		};
		MutableTreeNode leaf2[] = {
			new DefaultMutableTreeNode("彩峰 慧") ,
			new DefaultMutableTreeNode("榊 千鶴")
		};
		DefaultMutableTreeNode node1 =
			new DefaultMutableTreeNode("The forever that you wish");
		DefaultMutableTreeNode node2 =
			new DefaultMutableTreeNode("MUV-LUV");
		for(int i = 0 ; i < leaf1.length ;i++) node1.add(leaf1[i]);
		for(int i = 0 ; i < leaf2.length ;i++) node2.add(leaf2[i]);

		DefaultMutableTreeNode root = 
			new DefaultMutableTreeNode("Age");
		root.add(node1);
		root.add(node2);

		JTree tree = new JTree(root);
		tree.addTreeExpansionListener(this);

		getContentPane().add(new JScrollPane(tree));
		getContentPane().add(label , BorderLayout.NORTH);
	}
	public void treeExpanded(TreeExpansionEvent e) {
		label.setText("Expanded " + e.getPath().toString());
	}
	public void treeCollapsed(TreeExpansionEvent e) {
		label.setText("Collapsed " + e.getPath().toString());
	}
}
このプログラムは、上部のラベルに展開または収納された
ノードへのパスを表す文字列をイベント発生時に表示します


ノードの選択

ツリーの選択制御は、選択モデルとなるインターフェイスの登録で行います
ツリーは、デフォルトで用意されているモデルを採用していますが
必要に応じて、独自に作成した選択モデルを設定することも可能です
選択モデルは javax.swing.tree.TreeSelectionModel インターフェイスで表されます

public interface TreeSelectionModel

このインターフェイスで重要なのは、次のフィールド定数です

定数解説
int SINGLE_TREE_SELECTION 同時に複数のパスを指定することはできない
int CONTIGUOUS_TREE_SELECTION 選択範囲の項目は連続している必要がある
int DISCONTIGUOUS_TREE_SELECTION 選択範囲の項目数に制限はなく、各項目は連続している必要はない

これらの値は TreeSelectionModel.setSelectionMode() で設定し
TreeSelectionModel.getSelectionMode() で取得することができます

public void setSelectionMode(int mode)
public int getSelectionMode()

mode には新たに設定する選択モードを指定します
これを設定することによって、複数選択や単一項目選択に切り替えることができます
デフォルトでは DISCONTIGUOUS_TREE_SELECTION が設定されています

TreeSelectionModel の登録は JTree.setSelectionModel() メソッドで
モデルの取得は JTree.getSelectionModel() で行います

public void setSelectionModel(TreeSelectionModel selectionModel)
public TreeSelectionModel getSelectionModel()

selectionModel には新しく設定するツリーモデルを指定します
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;

public class Test extends JApplet {
	public void init() {
		MutableTreeNode node[] = {
			new DefaultMutableTreeNode("大空寺 あゆ") ,
			new DefaultMutableTreeNode("玉野 まゆ")
		};
		DefaultMutableTreeNode root = 
			new DefaultMutableTreeNode("The forever that you wish");
		for(int i = 0 ; i < node.length ;i++) root.add(node[i]);

		JTree tree = new JTree(root);
		tree.getSelectionModel().setSelectionMode(
			TreeSelectionModel.SINGLE_TREE_SELECTION
		);
		getContentPane().add(new JScrollPane(tree));
	}
}
このプログラムは、getSelectionModel() を呼び出してモデルを取得し
setSelectionMode() でモデルの選択モードを変更しています

TreeSelectionModel インターフェイスは様々なメソッドが宣言されており
これを実装するのは面倒なので、この場では省略します
通常は javax.swing.tree.DefaultTreeSelectionModel を使います
public class DefaultTreeSelectionModel extends Object
	implements Cloneable, Serializable, TreeSelectionModel
このクラスは、デフォルトコンストラクタのみを定義しています
開発者はこのクラスのインスタンスを生成してツリーに登録したり
あるいは、このクラスを拡張して独自の選択モデルを作成することができます



前のページへ戻る次のページへ