Eclipse Workbench以外でのEclipse GUIの使用: 第1回 スタンドアロン・モードでJFaceおよびSWTを使用する

シンプルなファイル・エクスプローラー・アプリケーションの作成

EclipseのGUIコンポーネント (JFaceおよびSWT) は、Eclipse Workbench内で使用されることがほとんどですが、実際にはそれ自体で必要な機能を備えた自己完結型フレームワークとして設計されています。JFaceは組み込み可能な設計になっており、Eclipse Workbenchの外でも驚くほど少ないコードで洗練されたGUIを作成できます。この3回シリーズの記事では、A. O. Van Emmenis氏がこのようなスタンドアロン・アプリケーションの作成方法について説明します。第1回では "Hello World" プログラムを例として、段階的にシンプルなファイル・エクスプローラー・アプリケーションを作成していきます。ここでは、いくつかの主要なJFaceクラス (およびSWTウィジェット) を、その使用に関するヒントやコツ、および設計上の問題点と合わせて紹介していきます。

Adrian Emmenis, Independent consultant

Photo of authorA. O. Van Emmenis氏は、Java/J2EEのトレーニングとコンサルティングを専門とする、イギリス、ケンブリッジを基盤に活躍する独立系コンサルタントです。Van氏は、これまで20年にわたってソフトウェア業界に関わってきました。CAD業界においてSmalltalkを使用したオブジェクトの操作からキャリアを開始し、現在は主にJavaを扱っています。彼は、特にアジャイル・メソッドとGUIの設計に関心を寄せています。Vanの連絡先は、van@vanemmenis.com です。



2001年 3月 01日

はじめに

Eclipseオープン・ソース・プロジェクトは、Javaの世界において最も興味深く新しい開発の1つです。Eclipse自体は「一種の汎用ツール・プラットフォームとして、言語に依存しない拡張可能なIDE (統合開発環境) を提供する」ことを目的としています。Eclipseについては、developerWorks の記事「Eclipse Platform入門」を参照してください。

Eclipseの2つの主要なコンポーネントは、SWTと呼ばれるグラフィカル・ライブラリーと、これに対応するJFaceと呼ばれるユーティリティ・フレームワークです。今回の記事では、これらのコンポーネントに焦点をあてて説明します。これらは、Eclipse WebサイトのTechnical Overview (参考文献を参照) で次のように説明されています。

  • SWT は、ネイティブなウィンドウ・システムに統合されているが、APIはOSには依存しないように作成された、ウィジェット・セットおよびグラフィカル・ライブラリーである。
  • JFace は、SWTを使用して実装されるUIツールキットであり、一般的なUIプログラミング・タスクを簡素化する。JFaceは、そのAPIと実装の両方においてウィンドウ・システムから独立しており、SWTをユーザーから隠蔽することなく、SWTとともに動作するよう設計されています。

図1は、Eclipse、JFace、およびSWTの関係を示しています。

図1. Eclipse Workbench、JFace、およびSWT
図1. Eclipse Workbench、JFace、およびSWT

JFaceとSWTについてこれまでに発表された記事のほとんどは、これらをより大きなEclipseフレームワークの中で使用するというものでした。今回の記事では、これまでとは異なる視点から論じていきます。ここでは、スタンドアロンJavaプログラムにおけるJFaceとSWTの使用について説明したいと思います。

例として、ファイル・エクスプローラー・アプリケーションを取り上げることにします。実際には、それほど現実に使用される機能を実装するわけではありませんが、フル機能のプログラムを作成する方法を理解するには十分なGUIを体験することができます。

インストール上の注意点

この記事のサンプル・ソース・コードをダウンロードできます。このソース・コードを実行するには、以下のシステム設定が必要です。

  • Windows 2000
  • Ecipse, Stable Build M3 (2002年11月15日)
  • Eclipseのインストール場所 - C:\eclipse-2.1.0

読者のシステムでプログラムが正しく動作するよう、以降は名前とファイルの区切り文字を自由に変更してください。

作成と実行の手順

クラスパスに次のJARファイルが必要です。

C:\eclipse-2.1.0\plugins\org.eclipse.jface_2.1.0\jface.jar

C:\eclipse-2.1.0\plugins\org.eclipse.runtime_2.1.0\runtime.jar

C:\eclipse-2.1.0\plugins\org.eclipse.swt.win32_2.1.0\ws\win32\swt.jar

C:\eclipse-2.1.0\plugins\org.eclipse.ui.workbench_2.1.0\workbench.jar

C:\eclipse-2.1.0\plugins\org.eclipse.core.runtime_2.1.0\runtime.jar

実行時にJava VM (仮想マシン) が、使用するGUIの正しい共有ライブラリーを選択するよう、次の引数を使用して実行してください。

		    -Djava.library.path=C:\eclipse-2.1.0\
                       plugins\org.eclipse.swt.win32_2.1.0\os\win32\x86\

最後に、サンプル・アプリケーションでアイコンを含むgifファイルを見つけられるよう、icons フォルダを含むフォルダからプログラムを実行してください。


"Hello, World"

まずは、最もシンプルなJFaceプログラムで、よくある "Hello, World" プログラムを作成してみましょう。

リスト1. Hello (バージョン1)
import org.eclipse.jface.window.*;
import org.eclipse.swt.widgets.*;

public class Hello
{
  public static void main(String[] args)
  {
    ApplicationWindow w = new ApplicationWindow(null);
    w.setBlockOnOpen(true);
    w.open();
    Display.getCurrent().dispose();
  }
}

Hello クラスのmainメソッドは、単にApplicationWindowを作成してオープンします。setBlockOnOpen() により、ウィンドウがクローズされるまでopen() はブロックされます。

ウィンドウがクローズされると、現在のDisplayが取得され破棄されます。これによりOSで使用されているリソースが解放されます (リソースの解放を常に行う理由については、後で説明します)。

このプログラムを実行すると、図2のようなウィンドウが表示されます。

図2. Hello (バージョン2)
図2. Hello (バージョン2)

これで終わりです。ここではまだ、ウィンドウには何も表示されません。これを修正する前に、JFaceウィンドウについて説明しましょう。


JFaceアプリケーション・ウィンドウ

ウィンドウとは、トップ・レベル・ウィンドウ用のJFace クラス、つまりOSのウィンドウ・マネージャーによって管理されるウィンドウのことをいいます。しかし、JFaceウィンドウはトップ・レベル・ウィンドウに対する実際のGUIオブジェクトではありません (SWTにはすでにShell と呼ばれるウィンドウ作成用のウィジェットが用意されています)。JFaceウィンドウは、対応するSWT Shellオブジェクトの情報を持つヘルパー・オブジェクトで、SWT Shellオブジェクトを作成または編集したり、そのイベントをリッスンするためのコードを提供します。図3は、ユーザー・コード、JFace、およびSWTの関係を表しています。

図3. ユーザー・コード、JFaceウィンドウ、およびSWT Shellの関係
図3. ユーザー・コード、JFaceウィンドウ、およびSWT Shellの関係

JFaceの動作について理解するにはこのモデルが大変重要です。JFaceウィンドウはSWTの実際の上位レイヤーではなく、SWTをユーザーから隠蔽しません。代わりにJFaceは、SWTのいくつかの共通した使用パターンをより簡単にプログラミングするためのユーティリティ・コードを提供します。

JFaceによって、ユーザーが使用するオブジェクトやサブクラス化の可能なクラスが提供されます。

前述のコード例ではApplicationWindow をそのまま使用していますが、実際にはサブクラス化を利用して、ユーザーの目的に合った振る舞いを定義できるように設計されています。メニュー・バー、ツール・バー、アプリケーション固有のコンテンツを挿入する領域、およびステータス行それぞれを作成する既成のユーティリティ・コードが用意されていて、それらをオプションで使用することもできます。図4は、JFaceファイル・エクスプローラーでのこれらの領域を示しています。

図4. アプリケーション・ウィンドウの各部
図4. アプリケーション・ウィンドウの各部

それでは、Helloを改良してApplicationWindow のサブクラスを作成してみましょう。変更した行は強調表示してあります。

リスト2. Hello (バージョン2)
import org.eclipse.jface.window.*;
import org.eclipse.swt.widgets.*;

public class Hello extends ApplicationWindow
{
  public Hello()
  {
    super(null);
  }

  public static void main(String[] args)
  {
    Hello w = new Hello();
    w.setBlockOnOpen(true);
    w.open();
    Display.getCurrent().dispose();
  }
}

コンストラクターでは、通常通り、スーパークラスのコンストラクターを呼び出す必要があります。今はこのコンストラクターの話はやめておきましょう。

このプログラムを実行しても、その結果は前のプログラムと何も変わりません。デフォルトでは、何の飾りもついていません。

ここで "Hello, World" というテキストを持つボタンを作成します。このボタンは、コンテンツ領域に表示されるようにします。そのためには、Control createContents(Composite parent) メソッドを実装する必要があります。

ApplicationWindow は、ほかのすべてのウィジェットが作成された後、ウィンドウが画面に表示される前にこのメソッドを呼び出します。

引数のparentは、コンテンツ領域を表すCompositeウィジェットです。

このメソッドでは、Compositeウィジェットを作成してparentに追加し、そこへほかのウィジェットを追加して、出来上がったCompositeウィジェットを返します。図5は、インスタンスの階層を示しています。

図5. アプリケーション・ウィンドウのインスタンスの階層
図5. アプリケーション・ウィンドウのインスタンスの階層

現時点でのコンテンツは、リスト3に示すように、parentにボタンを1つ追加した非常にシンプルなものです。

リスト3. Hello (バージョン3)
import org.eclipse.jface.window.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;

public class Hello extends ApplicationWindow
{
  public Hello()
  {
    super(null);
  }

  protected Control createContents(Composite parent)
  {
    Button b = new Button(parent, SWT.PUSH);
    b.setText("Hello World");
    return b;
  }

  public static void main(String[] args)
  {
    Hello w = new Hello();
    w.setBlockOnOpen(true);
    w.open();
    Display.getCurrent().dispose();
  }
}

結果は、図6のようになります。

図6. Hello (バージョン3)
図6. Hello (バージョン3)

さあ、できました。JFaceでの最初の "Hello, World" プログラムです。1つのボタンを持つウィンドウが完成しました。

それではファイル・エクスプローラーに移りましょう。まずは、フォルダー階層を表示するツリー形式のビューアーを作成します。


TreeViewerの使用

ApplicationWindow と同様に、TreeViewer も実際のSWTウィジェットではなく、SWTウィジェットを隠蔽もしません。TreeViewerでは、SWTのTreeウィジェットとその他のいくつかのオブジェクトを使用して項目を表示します。

ApplicationWindow とは異なり、JFaceのTreeViewer はサブクラス化することを目的としていません。

これは、TreeViewer が表示対象となるツリーのルートの要素情報を持つためです。もちろん、TreeViewer: void setInput(Object rootElement) のように、TreeViewerにそのオブジェクトが何かを知らせる必要はあります。

始めに、TreeViewerはルートとなる要素にその子要素を要求し、それらを表示します。以降は、ユーザーが子要素を展開するたびに、TreeViewerがそのノードの子要素を要求します。しかし、実際の動作はこれとは多少異なります。TreeViewer はドメイン・オブジェクトと直接やりとりはしません。その代わりにContentProvider と呼ばれる別のオブジェクトを利用してユーザーのドメイン・オブジェクトを使用します。図7を参照してください。

図7. TreeViewer、ContentProvider、およびドメイン・オブジェクト
図7. TreeViewer、ContentProvider、およびドメイン・オブジェクト

当然ContentProvider を実装する必要があります。TreeViewer では、クラスにITreeContentProvider インターフェースを実装する必要があります。


TreeContentProviderの実装

実装するメソッドは6つあります。実際には、この中の3つのメソッドだけを実装します。すぐに結果を見るためにも、ここではこの3つのメソッドに絞って考察することにします。

ツリー・ビューアーは下のようにして、コンテンツ・プロバイダーにルート要素の直下にあるトップレベルの要素群を要求します。

ITreeContentProvider: public Object[] getElements(Object element)

特定の要素の子要素が必要になるたびに、ツリー・ビューアーは次のメソッドを使用します。

ITreeContentProvider: public Object[] getChildren(Object element)

ノードに子要素がある (ノードの横に小さなプラス記号を表示する) かどうかを確認するため、ツリー・ビューアーは単にそのノードの子要素の数を問い合わせます。この動作をより高速に実行するには、もう1つ次のメソッドを実装する必要があります。

public boolean hasChildren(Object element)

おわかりのように、コンテンツ・プロバイダーはドメイン・オブジェクトへの参照を保持しません。これらの情報はツリー・ビューアー自体が保持しており、コンテンツ・プロバイダーの各メソッドに引数として渡します。

この例では、File オブジェクトがノードです。子要素を取得するには、listFiles() を使用します。listFiles() からnullが返された場合は、空の配列を作成することを忘れないで下さい。

ルート要素のすぐ下のトップレベル要素を取得するには、ここでもgetChildren() メソッドを使用します。

reveal(Object element) メソッドがgetParent() メソッドを使って実装されます。これにより、ツリー・ビューアーが自身のSWT Treeウィジェットをスクロールして、ツリー内の特定のノードを表示できるようになります。現在、目的のノードが実際に表示されていなければ、JFaceはそのノードを探しにいきます。JFaceは、目的のノードに到達するまで、そのノードの親、親の親という順に検索し、その後再びツリーを下って目的のノードを表示します。

hasChildren() メソッドの動作は最適化されたものではなく、明らかなことをしているだけです。結果として、リスト4のコードができました。

リスト4. FileTreeContentProvider (バージョン1)
import java.io.*;
import java.util.*;
import org.eclipse.jface.viewers.*;

public class FileTreeContentProvider implements ITreeContentProvider
{
  public Object[] getChildren(Object element)
  {
    Object[] kids = ((File) element).listFiles();
    return kids == null ? new Object[0] : kids;
  }

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

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

  public Object getParent(Object element)
  {
    return ((File)element).getParent();
  }
  
  public void dispose()
  {
  }

  public void inputChanged(Viewer viewer, Object old_input, Object new_input)
  {
  }
}

トップレベルExplorerクラスの実装

ここでは、Hello, Worldプログラムを使用します。プログラムの名前を変更し、createContents() メソッドではボタンを作成する代わりにTreeViewer を作成します。また、TreeViewer のコンテンツ・プロバイダーをこの例のファイル・ツリー・コンテンツ・プロバイダーに設定し、入力をフォルダーに設定します。この例では、C: ドライブのトップレベル・フォルダーを選択します。

ここでは、createContents() からSWTウィジェットを返す必要があることに注意してください。前述のように、JFaceのTreeViewerはSWTウィジェットではありませんから、これを返すことはできません。ツリー・ビューアーで実際のウィジェットを取得する必要があります。ここでは、getTree() を使用します。

現在のメイン・ウィンドウ・クラスは次のようになります。

リスト5. Explorer (バージョン1)
import java.io.*;

import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;

public class Explorer extends ApplicationWindow
{
  public Explorer()
  {
    super(null);
  }

  protected Control createContents(Composite parent)
  {
    TreeViewer tv = new TreeViewer(parent);
    tv.setContentProvider(new FileTreeContentProvider());
    tv.setInput(new File("C:\\"));
    return tv.getTree();
  }

  public static void main(String[] args)
  {
    Explorer w = new Explorer();
    w.setBlockOnOpen(true);
    w.open();
    Display.getCurrent().dispose();
  }
}

このプログラムを実行すると、図8のようなウィンドウが表示されます。

図8. Explorer (バージョン1)
図8. Explorer (バージョン1)

定型コードを除けば、Hello, Worldプログラムにわずか9行を加えただけでこれを実現できました。

ご想像どおり、ファイルはFile のtoString() メソッドを使用して表示されているのですが、それは本来ここで目指している方法ではありません。これを変更するには、ラベル・プロバイダーが必要です。


ラベル・プロバイダーの実装

ツリー・ノードの子要素を取得するためにコンテンツ・プロバイダー・オブジェクトがあるのと同様に、実際にノードを表示する場合、ツリー・ビューアーにはラベル・プロバイダーという別のヘルパー・オブジェクトが存在します。前と同様に、それを設定しなくてはいけません。

public void setLabelProvider(IBaseLabelProvider labelProvider)

また、各要素の表示用テキストを返す次のメソッドも実装する必要があります。

public String getText(Object element)

ツリー・ビューアーの図式にラベル・プロバイダーを追加すると、図9のようになります。

図9. コンテンツ・プロバイダーとラベル・プロバイダーを表すツリー・ビューアー
図9. コンテンツ・プロバイダーとラベル・プロバイダーを表すツリー・ビューアー

ILabelProvider というインターフェースを実装することもできますが、デフォルトで実装されるLabelProvider をサブクラス化する方が簡単です (このクラスは、ラベル・プロバイダーを明示的に設定しない場合に使用されます)。

getText() で実行したいことは、toString() がデフォルトで使用する絶対的なファイル名ではなく、ファイル名の最後の部分、つまり相対的なファイル名を返すことです。リスト6はこのコードを示しています。

リスト6. FileTreeLabelProvider (バージョン1)
import java.io.*;
import org.eclipse.jface.viewers.*;

public class FileTreeLabelProvider extends LabelProvider
{
  public String getText(Object element)
  {
    return ((File) element).getName();
  }
}

またリスト7に示すように、ツリー・ビューアーがこのラベル・プロバイダーを使用するよう指定しなければなりません。

リスト7. Explorer (バージョン2)
import java.io.*;

import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;

public class Explorer extends ApplicationWindow
{
  public Explorer()
  {
    super(null);
  }

  protected Control createContents(Composite parent)
  {
    TreeViewer tv = new TreeViewer(parent);
    tv.setContentProvider(new FileTreeContentProvider());
    tv.setLabelProvider(new FileTreeLabelProvider());
    tv.setInput(new File("C:\\"));
    return tv.getTree();
  }

  public static void main(String[] args)
  {
    Explorer w = new Explorer();
    w.setBlockOnOpen(true);
    w.open();
    Display.getCurrent().dispose();
  }
}

現時点でプログラムを実行すると、図10のように、外観のすっきりした画面が表示されます。

図10. Explorer (バージョン2)
図10. Explorer (バージョン2)

次はツリー・ビューアーを左に移動し、ツリー・ビューアーで選択したフォルダーに含まれるファイルのリストを表示するテーブル・ビューをその右側に追加します。


テーブル・ビューアーの使用

JFaceでは、TableViewer を使ってテーブルを処理します。TreeViewer と同様に、TableViewer にも入力 (ルート) オブジェクト、コンテンツ・プロバイダー、およびラベル・プロバイダーがあります。TableViewerはツリーを処理する必要がないため、TreeViewerよりシンプルです。図11は、コンテンツ・プロバイダーとラベル・プロバイダーを示しています。

図11. コンテンツ・プロバイダーとラベル・プロバイダーを表すテーブル・ビューアー
図11. コンテンツ・プロバイダーとラベル・プロバイダーを表すテーブル・ビューアー

入力オブジェクトを設定するメソッドは、前述のコードと同様、次のようになります。

TableViewer: void setInput(Object rootElement)


ファイル・テーブル・ビューアーのコンテンツ・プロバイダーの実装

コンテンツ・プロバイダーについて見てみましょう。今回のルート要素は、ツリー・ビューアーのルート要素よりシンプルです。テーブル・ビューアーは、ルート・オブジェクトにいくつかの子要素があると予測しているので、実装する必要があるのは、その子要素を取得する次のメソッドだけです。

public Object[] getElements(Object rootElement)

実装するインターフェースはIStructuredContentProvider です。

ルート・オブジェクトはフォルダーになり、その子要素は、ルート・オブジェクトに含まれるファイルまたはフォルダー (あるいはその両方) となります。したがって、ここで作成するファイル・テーブルのコンテンツ・プロバイダー・クラスはリスト8のようになります。

リスト8. FileTableContentProvider (バージョン1)
import java.io.*;

import org.eclipse.jface.viewers.*;

public class FileTableContentProvider implements IStructuredContentProvider
{
  public Object[] getElements(Object element)
  {
    Object[] kids = null;
    kids = ((File) element).listFiles();
    return kids == null ? new Object[0] : kids;
  }

  public void dispose()
  {
  }

  public void inputChanged(Viewer viewer, Object old_object, Object new_object)
  {
  }
}

これで、ツリー・ビューアーとテーブル・ビューアーの2つのビューアーができました。これらを隣合わせに配置するには、SWTのSashFormウィジェットを作成します。このウィジェットは、自身の子要素を境界で区切ります。この境界の位置はユーザーが変更できます。SashFormウィジェットを作成したら、そこにツリーとテーブルを追加します (図12)。

図12. ツリー・ビューアーとテーブル・ビューアーを含むSashForm
図12. ツリー・ビューアーとテーブル・ビューアーを含むSashForm

次に、ツリー・ビューアーでユーザーが選択した各フォルダーをテーブル・ビューアーで表示できるよう設定します。そのためには、イベントを リッスンする必要があります。


イベントのリスニング

ユーザーがツリー・ビューアーで項目を選択すると、ツリー・ビューアーはイベントSelectionChangedEvent を開始します。そこでこのイベントをリッスンし、このイベントが開始されたら、テーブルへの入力オブジェクトとして、現在ツリー・ビューアーで選択されているファイルを設定する必要があります。

ツリー・ビューアーでの選択変更イベントをリッスンするには、以下を使用します。

public void addSelectionChangedListener(ISelectionChangedListener listener)

ユーザーがツリー・ビューアー内のノードを選択または選択解除すると、選択変更用のリスナーが次のように呼び出されます。

public void selectionChanged(SelectionChangedEvent event)

このリスナー・クラスを実装するために、メインのExplorerウィンドウに匿名クラスのコードを記述します。selectionChanged() メソッドでは、選択されたばかりのオブジェクトを取得して、テーブル・ビューアーへの入力オブジェクトにする必要があります。これらをすべてまとめると、リスト9のようになります。

リスト9. Explorer (バージョン3)
import java.io.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.*;
import org.eclipse.swt.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.widgets.*;

public class Explorer extends ApplicationWindow
{
  public Explorer()
  {
    super(null);
  }

  protected Control createContents(Composite parent)
  {
    SashForm sash_form = new SashForm(parent, SWT.HORIZONTAL | SWT.NULL);

    TreeViewer tv = new TreeViewer(sash_form);
    tv.setContentProvider(new FileTreeContentProvider());
    tv.setLabelProvider(new FileTreeLabelProvider());
    tv.setInput(new File("C:\\"));

    final TableViewer tbv = new TableViewer(sash_form, SWT.BORDER);
    tbv.setContentProvider(new FileTableContentProvider());

    tv.addSelectionChangedListener(new ISelectionChangedListener()
    {
      public void selectionChanged(SelectionChangedEvent event)
      {
        IStructuredSelection selection =
          (IStructuredSelection) event.getSelection();

        Object selected_file = selection.getFirstElement();
        tbv.setInput(selected_file);
      }
    });
    
    return sash_form;
  }

  public static void main(String[] args)
  {
    Explorer w = new Explorer();
    w.setBlockOnOpen(true);
    w.open();
    Display.getCurrent().dispose();
  }
}

このプログラムを実行すると、図13のような結果が得られます。

図13. Explorer (バージョン3)
図13. Explorer (バージョン3)

ツリー・ビューアーと同様、テーブル・ビューアーで明示的にラベル・プロバイダーを設定しなければ、デフォルトのラベル・プロバイダーが使用されます。ここでは、そのデフォルトのラベル・プロバイダーを使用しています。前に説明したように、デフォルトの振る舞いでは、要素のtoString() メソッドによって返される文字列、つまり絶対的なファイル名が表示されます。

それではここで独自のテーブル・ラベル・プロバイダーを実装してみましょう。


ファイル・テーブルのラベル・プロバイダーの実装

ここで必要なメソッドは、次の1つだけです。

public String getColumnText(Object element, int column)

引数は、ラベルの取得対象となる要素と、列インデックス (0から始まる) の2つです。

列インデックスを無視すれば、この実装はリスト10のようにとてもシンプルになります。

リスト10. FileTableLabelProvider (バージョン1)
import java.io.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.graphics.*;

public class FileTableLabelProvider implements ITableLabelProvider
{
  public String getColumnText(Object obj, int i)
  {
    return ((File) obj).getName();
  }

  public void addListener(ILabelProviderListener ilabelproviderlistener)
  {
  }

  public void dispose()
  {
  }

  public boolean isLabelProperty(Object obj, String s)
  {
    return false;
  }

  public void removeListener(ILabelProviderListener ilabelproviderlistener)
  {
  }
  
  public Image getColumnImage(Object arg0, int arg1)
  {
    return null;
  }
}

"Name" とラベル付けされたヘッダーを持つ1つの列を含むテーブルを設定するには、リスト11のように、テーブル・ビューアーからTableウィジェットを抽出し、TableColumnウィジェットをその子要素として作成してプロパティを設定する必要があります。

リスト11. Explorer (バージョン4)
import java.io.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.*;
import org.eclipse.swt.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.widgets.*;

public class Explorer extends ApplicationWindow
{
  public Explorer()
  {
    super(null);
  }

  protected Control createContents(Composite parent)
  {
    SashForm sash_form = new SashForm(parent, SWT.HORIZONTAL | SWT.NULL);

    TreeViewer tv = new TreeViewer(sash_form);
    tv.setContentProvider(new FileTreeContentProvider());
    tv.setLabelProvider(new FileTreeLabelProvider());
    tv.setInput(new File("C:\\"));

    final TableViewer tbv = new TableViewer(sash_form, SWT.BORDER);
    tbv.setContentProvider(new FileTableContentProvider());
    tbv.setLabelProvider(new FileTableLabelProvider());

    TableColumn column = new TableColumn(tbv.getTable(), SWT.LEFT);
    column.setText("Name");
    column.setWidth(200);
    tbv.getTable().setHeaderVisible(true);

    tv.addSelectionChangedListener(new ISelectionChangedListener()
    {
      public void selectionChanged(SelectionChangedEvent event)
      {
        IStructuredSelection selection =
          (IStructuredSelection) event.getSelection();

        Object selected_file = selection.getFirstElement();
        tbv.setInput(selected_file);
      }
    });
    return sash_form;
  }

  public static void main(String[] args)
  {
    Explorer w = new Explorer();
    w.setBlockOnOpen(true);
    w.open();
    Display.getCurrent().dispose();
  }
}

これを実行すると、結果は 図14のようになります。

図14. Explorer (バージョン4)
図14. Explorer (バージョン4)

まとめ

短時間ではありましたが、さまざまなJFaceを紹介してきました。1つのアプリケーション・ウィンドウと2つのビューアー (ツリー・ビューアーとテーブル・ビューアー) を使用し、それぞれにコンテンツ・プロバイダーとラベル・プロバイダーを実装しました。また、Button、SashForm、Table、TableColumnなどのSWTウィジェットを使用し、イベント・リスナーを実装しました。

ただし、不完全な部分もいくつかあります。コンテンツ・プロバイダーとラベル・プロバイダーでいくつかのメソッドを省略しましたし、ツリー・ビューアーにはフォルダー以外にファイルも表示されています。また、アイコンはまったく表示されていませんし、メニュー・バー、ツール・バー、ステータス行、その他のポップアップ・メニューなどはまったくありません。

次回の記事では、コンテンツ・プロバイダーとラベル・プロバイダーの見栄えを良くし、各ビューアーでソートとフィルタリングを実行します。またウィンドウにステータス行を追加し、両方のビューアーにアイコンを追加して、JFaceのイメージ・レジストリーについて学習します。

参考文献

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source, Java technology
ArticleID=236392
ArticleTitle=Eclipse Workbench以外でのEclipse GUIの使用: 第1回 スタンドアロン・モードでJFaceおよびSWTを使用する
publish-date=03012001