ビューとビューア

作成 2003/1/1

JFaceビューアは、ツリーやテーブルといった構造化モデルを扱うための仕組みです。ここではツリービューアを利用して、簡単なリソースビューを作成してみます。

動作環境

ここでは、以下の環境で作成を行いました。

プラグインプロジェクト、ViewPartの作成

プラグインプロジェクトを作成し、plugin.xmlを編集します。ここでは、com.muimi.treeという名前でプロジェクトを作成しました。また、plugin.xmlを以下のように編集します。

最初のプラグインの手順で作ってもいいし、最初のプラグインで作成したplugin.xmlをコピーして、修正してもよいでしょう(ソースを手で修正した場合は、クラスパスの更新も忘れずに)。今回はリソースAPIを使うのでorg.eclipse.core.resourcesもimportしています。

リスト plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<plugin
   id="com.muimi.tree"
   name="com.muimi.tree"
   version="1.0.0">

   <runtime>
      <library name="tree.jar"/>
   </runtime>

   <requires>
      <import plugin="org.eclipse.ui"/>
      <import plugin="org.eclipse.core.resources"/>
   </requires>

   <extension
         point="org.eclipse.ui.views">
      <view
            name="tree sample"
            class="com.muimi.tree.ViewPart1"
            id="com.muimi.tree.view1">
      </view>
   </extension>

</plugin>

ビューアの作成

ビューアにはいくつかの種類のものが用意されています。ここでは、TreeViewerクラスを利用します。

画面 ビューアのクラス階層

リスト ビューアの作成

public class ViewPart1 extends ViewPart {

    private TreeViewer treeViewer;

    public void createPartControl(Composite parent) {

        treeViewer = new TreeViewer(parent);
    }

    //....
}

ビューアにはContentProviderとLabelProviderという重要な2つのプロバイダークラスがあります。この2つのプロバイダークラスを通して、対象とするモデルオブジェクトを操作、表示します。ContentProviderの方は、モデル間の構造を定義します。LabelProviderは、モデルの表示名やイメージを定義します。

ContentProvider

まず、ContentProviderを実装、セットします。最初のバージョンのViewPart1クラスは次のようになります。

リスト ViewPart1.java バージョン1

package com.muimi.tree;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

public class ViewPart1 extends ViewPart {

    private TreeViewer treeViewer;


    public void createPartControl(Composite parent) {

        treeViewer = new TreeViewer(parent);
        
        //ContentProviderをセット
        treeViewer.setContentProvider(new TContentProvider());

        //入力モデルをセット
        treeViewer.setInput(ResourcesPlugin.getWorkspace().getRoot());
    }


    public void setFocus() {
    }


    //ContentProviderクラス
    class TContentProvider implements ITreeContentProvider {

        public Object[] getChildren(Object parent) {
            if (parent instanceof IContainer) {
                try {
                    return ((IContainer) parent).members();
                } catch (CoreException e) {
                    e.printStackTrace();
                }
            }

            return new Object[0];
        }

        public Object getParent(Object element) {
            return null;
        }

        public boolean hasChildren(Object element) {
            return getChildren(element).length > 0;
        }

        public Object[] getElements(Object input) {
            return getChildren(input);
        }

        public void dispose() {
        }

        public void inputChanged(
            Viewer viewer,
            Object oldInput,
            Object newInput) {
        }
    }
}

簡単のため、インナークラスを使っていますが、特にインナークラスを使わなければならない理由はありません。

TContentProviderのgetChildren()メソッドでは、親モデルを引数に子モデルの配列を返します。ここでは、リソースAPIのIContainer#members()メソッドを使っています。リソースAPIについてはここでは、説明しませんが、members()で子要素の一覧を返します。hasChildren()メソッドでは、getChildren()メソッドの結果から子要素があるかを調べています。getElements()メソッドは、setInputの後に呼ばれますが、ここではgetChildren()を呼んでいるだけです。

PDEワークベンチを実行し、ビューを表示すると、ワークスペースのリソースがツリーで表示されるのがわかります。まだ、LabelProviderを指定していないので、デフォルトのラベルプロバイダが利用され、モデルをtoString()されたものが表示されています。


LabelProvider

次にLabelProviderをセットします。変更部分は太字にしてあります。

リスト LabelProviderのセット

public class ViewPart1 extends ViewPart {

    private TreeViewer treeViewer;

    public void createPartControl(Composite parent) {

        treeViewer = new TreeViewer(parent);
        treeViewer.setContentProvider(new TContentProvider());
        treeViewer.setLabelProvider(new TLabelProvider());
        treeViewer.setInput(ResourcesPlugin.getWorkspace().getRoot())
    }

    //...

    //LabelProviderクラス
    class TLabelProvider extends LabelProvider {

        public String getText(Object element) {
            return ((IResource) element).getName();
        }
    }

getText()メソッドで表示する文字列を返します。ここではリソースAPIのIResource#getName()メソッドを利用しています。実行すると次のようにちゃんと、フォルダ名、ファイル名が表示されているのがわかります。


次にgetImage()メソッドをオーバーライドして、イメージを表示します。イメージはプラグイン毎にgifファイルなどを読みこんで表示でいますが、ここでは、ワークベンチの共通イメージを利用しています。IContainer(子要素を持つコンテナ)だったら、フォルダのイメージを返しています。

    class TLabelProvider extends LabelProvider {

        public Image getImage(Object element) {
            if (element instanceof IContainer) {
                return PlatformUI.getWorkbench().getSharedImages().getImage(
                    ISharedImages.IMG_OBJ_FOLDER);
            } else {
                return PlatformUI.getWorkbench().getSharedImages().getImage(
                    ISharedImages.IMG_OBJ_FILE);
            }
        }

        public String getText(Object element) {
            return ((IResource) element).getName();
        }
    }

実行すると、フォルダとファイルで異なるイメージが表示されているのがわかります。


DoubleClickListener

以上で、基本部分は終了ですが、せっかくなのでもう少し機能拡張してみましょう。ツリーの要素をダブルクリックしたときに関連づけられたエディタで開くようにしてみます。

public class ViewPart1 extends ViewPart {

    private TreeViewer treeViewer;

    public void createPartControl(Composite parent) {

        treeViewer = new TreeViewer(parent);
        treeViewer.setContentProvider(new TContentProvider());
        treeViewer.setLabelProvider(new TLabelProvider());
        treeViewer.setInput(ResourcesPlugin.getWorkspace().getRoot());
        treeViewer.addDoubleClickListener(new DoubleClickListener());
    }

    //....

    class DoubleClickListener implements IDoubleClickListener {

        public void doubleClick(DoubleClickEvent event) {
            IResource file =
                (IResource) ((StructuredSelection) event.getSelection())
                    .getFirstElement();
            if (file instanceof IFile) {
                try {
                    PlatformUI
                        .getWorkbench()
                        .getActiveWorkbenchWindow()
                        .getActivePage()
                        .openEditor(
                        (IFile) file);
                } catch (PartInitException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

event.getSelection()で選択されている要素を取得します。TreeViewerのStructuredSelectionにキャストして、最初の要素を取得しています。モデルは必ずリソースなのでIResourceにキャストしています。で、リソースがファイル(IFile)だったら、デフォルトのエディタで開いています。

画面は、ちょっとわかりづらいですが、ファイルをダブルクリックするとエディタで開きます。


SelectionProvider

次はViewPartのSelectionProviderをセットします。

public class ViewPart1 extends ViewPart {

    private TreeViewer treeViewer;

    public void createPartControl(Composite parent) {

        treeViewer = new TreeViewer(parent);
        treeViewer.setContentProvider(new TContentProvider());
        treeViewer.setLabelProvider(new TLabelProvider());
        treeViewer.setInput(ResourcesPlugin.getWorkspace().getRoot());
        treeViewer.addDoubleClickListener(new DoubleClickListener());
        getSite().setSelectionProvider(treeViewer);
    }

    //...
}

選択したモデルがプロパティービューで表示されます。


なお、これだけの処理でプロパティービューに表示されるのは、利用しているモデル(IResource)でその機能が提供されているからです。自作モデルでこのように表示させるには、IPropertySourceインターフェイスを実装するか、IAdaptableを実装する必要があります。

まとめ

リソースAPIを使っているので、一見わかりにくいかもしれませんが、コードが短いのでよしとしましょう。

その他に基本機能として、アクション(メニュー、ツールバー、ポップアップ)、ソーター、フィルターなどを利用することも多いでしょう。以下のサンプルには、これらの実装されていますので、興味のある人は見てみてください。説明はしょりすぎ?

ここまでのプラグインはこれ→com.muimi.tree_1.0.0.zip


UP| TOP