TreeViewerその1

JFaceでツリー表示を行うにはorg.eclipse.jface.viewers.TreeViewer クラスを使用することになります。 SwingのJTreeに比べるとTreeViewerの枠組みのほうが色々と便利じゃないかなと 思うのですが、いかがでしょう。

Content Provider

TreeViewerではツリー表示したいオブジェクト(オブジェクト群というべきでしょうか) については特に制限がありません。関連付けを行うためにTreeViewerに渡して しまう(setInput()メソッドを使う)のですが、 TreeViewerはこれを直接アクセスするのではなく、Content Providerと呼ばれる、 org.eclipse.jface.viewers.IContentProviderインタフェースを 実装したクラスを通してアクセスするようになっています。 これはJFaceの他のxxxxViewerと同様の方法ですね。

TreeViewerの場合、IContentProviderのサブインタフェースである org.eclipse.jface.viewers.ITreeContentProviderインタフェースを 実装したクラスを、ツリー表示したいオブジェクトにあわせて作成することに なります。ITreeContentProviderには、親インタフェースで定義されている メソッドを含め6つのメソッドがあります。必ずしもこれら全てを実装する 必要はなく、本当に必要なものだけを用意すれば動作します(不要なものは 空の実装を用意しておく必要はあります)。

例えばXMLのタグ名をXMLの構造にあわせてツリー表示する場合を考えて みましょう。ツリー表示を行う対象のクラスはorg.w3c.dom.Document ということになりますので、Document用のContent Providerクラスとして、 DomTreeContentProviderを作成します。

public class DomTreeContentProvider
		implements ITreeContentProvider {

まずgetElements()メソッドを実装しましょう。このメソッドはTreeViewerの場合には ツリーのルートに表示したいオブジェクトを返すメソッドということになります。 TreeViewerでは一般にはツリーのルートになるノードは複数あっても良いのですが、 ここで作成しようとしているXMLの表示に限ればルートノード(Node)はただ1つ ですから、これを返すようなメソッドを作成します。

	public Object[] getElements(Object target) {
		if (target instanceof Document) {
			Document document = (Document) target;
			Element rootElement = document.getDocumentElement();
			Element[] nodes = new Element[1];
			nodes[0] = rootElement;
			return nodes;
		}
		return null;
	}

引数に渡されるtargetはTreeViewerのsetInput()メソッドに渡したオブジェクト です。念のためDocumentであるか確認した上で、ルートのノードを取り出し、 それをただ一つの要素としてもつオブジェクトの配列(ここではElementの配列 ですが)を返しています。

次にgetChildren()メソッドを実装します。これは引数で渡されたオブジェクト (これはツリー表示したい個々のオブジェクト)が渡されるので、その子となる オブジェクトを返すメソッドです。作成中のプログラムではElementオブジェクト が渡されるはずなので、その子ノードの配列を返すようにしています。

	public Object[] getChildren(Object parent) {
		if (parent instanceof Element) {
			List list = new ArrayList();
			Element element = (Element) parent;
			NodeList nodeList = element.getChildNodes();
			int n = nodeList.getLength();
			for (int i = 0; i < n; i++) {
				Node node = nodeList.item(i);
				if (node.getNodeType() == Node.ELEMENT_NODE) {
					list.add(node);
				}
			}
			if (list.size() > 0) {
				return list.toArray();
			}
		}
		return null;
	}

getParent()メソッドも実装しておきます。これはgetChildren()の反対、つまり 引数に渡されたオブジェクトの親にあたるオブジェクトを返すメソッドです。 これは簡単ですね。

	public Object getParent(Object child) {
		if (child instanceof Element) {
			Element element = (Element) child;
			return element.getParentNode();
		}
		return null;
	}

ツリー表示するノードが末端(leaf)かどうかで表示を変えたいということがあります。 TreeViewerではContent ProviderのhasChildren()メソッドの戻り値でその判断を 行います。XML文書の場合普通は常に子ノードを持つことができるので、ノードが 末端になることはありません。

	public boolean hasChildren(Object object) {
		if (object instanceof Element) {
			return true;
		} else {
			return false;
		}
	}

dispose()メソッドとinputChanged()メソッドは、今はいらないので空の実装にしておきます。これでDomTreeContentProviderクラスはひとまず作成完了です。

Lable Provider

Content ProviderだけですとTreeViewerはツリー構造へのアクセスはできますが、 それをどのように表示してよいかがわかりません。どのように表示するのかを TreeViewerに(xxxxViewer一般に)教えるのがLabel Providerと呼ばれるクラスです。 TreeViewerではorg.eclipse.jface.viewers.LabelProviderという デフォルトの実装がありますので、これをextendsしてLabel Providerを実装 するのが簡単です。LabelProvierクラスのままだと各オブジェクトをtoString() オブジェクトで文字列化したものを表示されてしまいますので、ここでは XMLのノードの名前を表示するようにしてみます。

public class DomTreeLabelProvider extends LabelProvider {

	public String getText(Object object) {

		if (object instanceof Element) {
			return ((Element) node).getNodeName();
		}
		return object.getClass().getName();
	}

}

これでツリー表示が可能になります。簡単でしょ。 上記のクラスをもう少しいじったもののサンプル表示が以下の様になります。

ツリー表示のサンプル
SWT, JFace  ソフトウェア研究室  PoisonSoft