表現力豊かなGUIでのビューは様々な形式で情報を表示できるため、ユーザーの使い勝手が非常に良くなります。UIのビューはその性格上、他のビューに依存し、他のビューと相互動作する必要があります。EclipseではUIビューのリンクが容易にできるだけではなく、非UIのシナリオでもビューのリンクを実現することができます。
Eclipseプラットフォームでは、プラグ可能コンポーネント、つまりプラグインを使って、表現力豊かなGUI(graphical user interface)アプリケーションを作ることができます。例えばプラグインは、GUIにビューをもたらします。しかし実世界のアプリケーションでのUIビューは、それ自身で独立、ということはありません。UIビューは、他のビューの状態に合わせて相互動作を行い、自分自身を更新する必要があります。
GUIアプリケーションの単純な例として、世界の有名観光地を説明するアプリケーションを下記に示しています。このGUIには、見どころと公共交通機関の情報を表示するSelect City(都市を選択)ビューがあります。
図1. ビューのリンクの例
この記事では、Eclipseでのビューを、他のビューの状態と協調、応答動作させるための方法を説明します。また、ある場合には、他の方法よりもビューをリンクする方法の方が良いことについても説明します。
Eclipse開発者がビューをリンクしようとする場合に使える方法としては、次のようなものがあります。
- セレクション・プロバイダーとセレクション・リスナーによるパターン。ビューは、他のビューで行われた選択に反応して動作します。
- 何らかのイベントと組み合わせて、IAdaptableインターフェースを使用する方法
- プロパティー変更リスナーを使用する方法。ビューは、登録したリスナーに対してプロパティー変更イベントをプッシュすることができます。
セレクション・プロバイダーとセレクション・リスナーによるパターン
セレクション・プロバイダーとセレクション・リスナーによるパターンは、他のビューで行われた変更に反応するビューを生成するために手軽な方法です。例えば、都市の名前を表すUIアイテムをユーザーがクリックすると、その都市の観光地の詳細を、他のビューが表示するような場合です。そうしたビューは、UI選択オブジェクト(都市の名前を表すストリング・オブジェクトなど)の中に含まれている情報を取り出し、その情報を使って、そのモデルから得られる追加情報を表示します。
ビューは、UI選択イベントを識別し、取り出せる必要があります。org.eclipse.ui.ISelectionListenerは、UI選択イベントを受信するリスナー・インターフェースです。このセレクション・リスナーは、ワークベンチ・ページに登録されている必要があります。ワークベンチ・ページは、org.eclipse.ui.ISelectionServiceインターフェースが定義するサービスを実装し、UI選択イベントをリスナーにソースとして提供するための協調動作を行います。セレクション・リスナーは、選択サービスに登録されている必要があります。
選択対象となり得るUIアイテムを表示するビューは、UI選択を公開できる機能も持っている必要があります。ビューにそうした機能を持たせるためには、「セレクション・プロバイダー」を、対応するワークベンチ・サイトに登録します。Eclipseの各UI部分は、org.eclipse.ui.IWorkbenchPartSite参照を介して、ワークベンチ・サイトと連絡を取りあいます。セレクション・プロバイダーは、ワークベンチ・サイトに登録されています。
セレクション・プロバイダーとセレクション・リスナーによるパターンを使ってビューがリンクされると、ビューは自分自身を、リスナーとしてワークベンチ・ページに追加します。選択を公開しようとする他のビューは、それぞれに対応するワークベンチ・サイトに対して、セレクション・プロバイダーを追加する必要があります。org.eclipse.ui.ISelectionListenerインターフェースを下記に示します。
public void selectionChanged(IWorkbenchPart part, ISelection selection); |
ビューが選択の変更をリスンできるようにするためには、ビューにISelectionListenerインターフェースを実装し、ビュー自身をワークベンチ・ページに登録する必要があります。リスト1は、その一例です。
リスト1. ワークベンチ・ページにセレクション・リスナーを登録する
public class MyView extends ViewPart implements ISelectionListener{
public void createPartControl(Composite parent) {
// add this view as a selection listener to the workbench page
getSite().getPage().addSelectionListener((ISelectionListener) this);
}
// Implement the method defined in ISelectionListener, to consume UI selections
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
//Examine selection and act on it!
}
}
|
より賢明な方法でUI選択を利用するためには、コンシューマー・ビューを、特定なビュー部分に対するリスナーとして登録します。その一例として下記の例では、ソース・ビュー部分のビューIDが、セレクション・リスナーを登録する際のパラメーターとして使われています。
getSite().getPage().addSelectionListener("SampleViewId",(ISelectionListener)this); |
この手法によって、コンシューマー・ビューへの冗長コールバックを無くすことができます(このビューが特定なリスナーではないものとして登録された場合には、冗長なコールバックが発生します)。
リスト2に示すコード断片は、あるビューのcreatePartControl() メソッドを示しています。このメソッドはJFace TableViewerを生成し、それをセレクション・プロバイダーとしてワークベンチ・サイトに登録します。このコードによって、TableViewer で行われるUI選択の変更が、すべてそのページに伝達され、最終的には、関心対象であるコンシューマー・ビューに伝達されます。
リスト2. セレクション・プロバイダーを設定する
public void createPartControl(Composite parent) {
// Set up a JFace Viewer
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setSorter(new NameSorter());
viewer.setInput(getViewSite());
// ADD the JFace Viewer as a Selection Provider to the View site.
getSite().setSelectionProvider(viewer);
} |
このビューは下記の2つの理由から、自分が生成したJFace TableViewerを、セレクション・プロバイダーとして登録するように選択します。
- このビューはTableViewerを使って情報を表示し、ユーザーはTableViewerとやり取りする。
- TableViewerは、セレクション・プロバイダー・インターフェースを実装しており、選択イベントをワークベンチ部分サイト(workbench part site)にソース提供する。
JFaceビューアーはセレクション・プロバイダーなので、ほとんどの場合、セレクション・プロバイダーを生成する必要はありません。ビューは単純に、数多くあるJFaceビューアーの1つを使ってデータを表示し、そのJFaceビューアーをセレクション・プロバイダーとして登録します。
下記のような一部の場合では、ビューのリンクに関して異なる手法が必要です。
- メモリー使用が増加したために、UI選択オブジェクトが効率的に保持するには情報量が大きくなりすぎた場合。
- ビューが、単なる視覚的選択ではない情報を公開しようとする場合。公開すべき情報は、選択に基づいて行われる後処理の結果、という場合もあります。
- ビューが、含まれているJFaceビューアーによるビューには全く寄与していない、別のプラグインからの情報を利用しようとする場合。この場合では、UI選択に基づくリンクを利用することはできません。
最初の問題は、org.eclipse.core.runtime.IAdaptableインターフェースを利用することで軽減することができます。このインターフェースによって、選択オブジェクトは、より多くの情報を、オンデマンドでソース提供することができます。問題2と3は、自作による手法が必要です。また、必要なものは、プロパティー変更リスナー・パターンのみであるかも知れません。
IAdaptableを実装するクラスには、あるタイプのアダプターを動的に返す機能があり、このアダプターを使って、さらに情報を検索することができます。ビューアーの中の選択オブジェクトがIAdaptableインターフェースを実装している場合には、(返されるアダプターのタイプによっては)こうしたオブジェクトを効果的に使って、追加情報や関連情報を検索することができます。org.eclipse.core.runtime.IAdaptableインターフェースを下記に示します。
public void object getAdapter(Class adapter); |
当然のことですが、呼び出し側は、その選択が返すべきアダプター・インターフェースのタイプを知っている必要があります。例えば、単一レベルのツリーとして都市を表現するように設定されたJFace TreeViewerを考えてみてください。都市を表現するオブジェクトは、CityClassというタイプです。CityClassオブジェクトは、その都市に関する何らかの予備情報を保持しておき、必要な時だけ詳細情報を返す必要があります。リスト3で、CityClassがサポートするアダプター・タイプに注意してください。呼び出し側は、さらに詳しい情報をオンデマンドで検索できるようになっています。
リスト3. JFace TreeViewerでのCityClass
class CityClass implements IAdaptable {
private String cityName;
public CityClass(String name) {
this.name = name;
}
public String getName() {
return name;
}
public CityClass getParent() {
return parent;
}
public String toString() {
return getName();
}
public Object getAdapter(Class key) {
if (key.getName().equals("ITransportationInfo"))
return CityPlugin.getInstance().getTransportAdapter();
else (key.getName().equals("IPlacesInfo"))
return CityPlugin.getInstance().getPlacesAdapter();
return null;
}
}
|
Eclipse IDEのワークベンチに慣れている開発者であれば、エディターの中で開いているファイルの構造ビューを表示するOutlineビューを知っているでしょう。このOutlineビューの例から分かることは、あるイベント・タイプと組み合わせてIAdaptableインターフェースを利用すると、他のビュー内容に基づいて効率的にビューを初期化できるということです。エディターは、ユーザーが編集のために開いたファイルに対するContent Outlineページを作成する必要があります。Content Outlineページは、IContentOutlinePageという、あるインターフェースに準拠しています。エディターは、IAdaptableインターフェースも実装している必要があります(そうすればエディターが、IContentOutlinePageというタイプのアダプターのクエリー対象となります)。このアダプターは、あるファイルに対するアウトライン情報を検索、表示するために使われます。
IAdaptableインターフェースの、もう一つの例がPropertiesビューです。Propertiesビューは、アクティブな部分の選択を追跡し、現在の選択オブジェクトに対するgetAdapterメソッドを呼び出します。クエリー対象のアダプター・タイプはIPropertySourceです。Propertiesビューは、今度はIPropertySourceアダプターを使って、表示すべき情報を検索します。
ビューのリンクに関するこうした例では、アプリケーションはSelection ChangedあるいはPart Activation通知を受信すると、IAdaptableを介して情報のプル(pull)を開始します。従って、もし選択がIAdaptableである場合には、ユーザーはアダプターを介することによって、(アダプターを使わずに選択オブジェクト自体から得られる情報よりも)ずっと多くの情報を検索することができます。
プロパティー変更リスナーを利用するタイプの相互動作を利用すると、先に挙げた2つの問題、つまり、何らビューに寄与しないプラグインからの情報をビューがどのように取り出すのか、また、視覚的な選択が行われる際に発生する処理で生成される情報をビューがどのように公開するのか、という問題に対応することができます。
このためには、プロパティー変更リスナーの登録を受け付け、必要に応じて登録リスナーへの通知まで行うようなプラグインを構築します。アプリケーションは、共有すべき情報も含んだ、カスタム化イベントをリスナーに通知します。
セレクション・プロバイダーの場合とは異なり、プロパティー変更プロバイダーが実装すべき特別なインターフェースはありません。ただし、生成されるプロバイダーにリスナーを登録するための意味体系を決める必要があります。リスト4のコード断片は、プロパティー・プロバイダーのビューやプラグイン・クラスにプロパティー変更リスナーを追加、削除するためのメソッドを示しています。
リスト4. プロパティー変更リスナーを追加、削除する
//To add a listener for property changes to this notifier:
public void addPropertyChangeListener(IPropertyChangeListener listener);
//To remove the given content change listener from this notifier:
public void removePropertyChangeListener(IPropertyChangeListener listener);
|
プロパティー・プロバイダーはorg.eclipse.jface.util.PropertyChangeEventを使って、読み込み、伝達を効率的に行えるイベントを生成します。また、リスナー・リストを維持管理し、リスナーにコールバックする責任は、プロパティー・プロバイダーにあります。
一例として、世界の主な都市の天気を表示するWorld Weather Web Serviceを1時間毎に呼び出し、その情報を他のプラグインやビューが利用できるようにするためのプラグインを考えてみてください。CityWeatherPluginはCitiesWeatherXMLというプロパティー公開し、コンシューマーは自分たちをPropertyChangeリスナーとしてCityWeatherPluginに登録するのです。これを実現するためには、リスナーは、自分たちを天気データ・イベントへのリスナーとして登録するために呼び出すべきメソッドとして、CityWeatherPluginにあるメソッドを知っている必要があります。CityWeatherPluginは、リスナーを追跡し、リスナーに対して通知しなければなりません。CityWeatherPluginは、PropertyChangeEventを使ってリスナーにデータを提供します。
リスト5. プロパティー・プロバイダーを生成する
class CityPopulationPlugin {
ArrayList myListeners;
// A public method that allows listener registration
public void addPropertyChangeListener(IPropertyChangeListener listener) {
if(!myListeners.contains(listener))
myListeners.add(listener);
}
// A public method that allows listener registration
public void removePropertyChangeListener(IPropertyChangeListener listener) {
myListeners.remove(listener);
}
public CityPopulationPlugin (){
// method to start the thread that invokes the population \
web service once every hour
// and then notifies the listeners via the propertyChange() callback method.
initWebServiceInvokerThread( myListeners );
}
void initWebServiceInvokerThread(ArrayList listeners) {
// Code to Invoke Web Service Periodically, and retrieve information
// Post Invocation, inform listeners
for (Iterator iter = listeners.iterator(); iter.hasNext();) {
IPropertyChangeListener element = (IProperty\
ChangeListener) iter.next();
element.propertyChange(new PropertyChangeEvent(this, \
"CitiesWeatherXML" , null , CityWeatherXMLObj));
}
}
}
|
プロパティー変更リスナーは、プロパティー変更プロバイダーからのコールバックをイネーブルにするためにorg.eclipse.jface.util.IPropertyChangeListenerインターフェースを実装する必要があります。このインターフェースには、public void propertyChange(PropertyChangeEvent event) という1つのメソッドがあります。
リスト6. IPropertyChangeListenerを実装する
class MyView implements IPropertyChangeListener {
public void createPartControl() {
//register with a Known Plugin that sources Population Data
CityPopulationPlugin.getInstance().addPropertyChangeListener(this);
}
public void propertyChange(PropertyChangeEvent event) {
//This view is interested in the Population Counts of the Cities.
//The population data is being sourced by another
plugin in the background.
if( event.getProperty().equals("CitiesWeatherXML")) {
Object val = event.getNewValue();
// do something with val
}
}
}
|
この方法は、必要なシナリオに応じてアプリケーションが様々な方法でリスナーに通知し、情報を渡せるという意味で、より柔軟です。渡される情報は、UI選択と直接関係している必要はなく、何らかの後処理の結果であっても構いません。あるいは、他の背景ジョブの状態に関連付けられていたり、モデルから取り出した最新情報の周期的プッシュであったりする場合もあります。例えばCity Selector Viewは、選択された都市の情報を伝達するだけではなく、PropertyChangeの方法を利用して、現在選択されている都市の天気情報を他のコンシューマーに対して非同期的にプッシュします。
この記事では、ビュー同士が協調動作し、お互いに応答し合うようにするための方法を幾つか説明しました。もしUI選択そのもので不十分な場合には、IAdaptableインターフェースによってUI選択を強化することができます。プロパティー変更リスナーは、より柔軟であり、非UIのシナリオにも使用することができます。
学ぶために
-
Eclipse.orgには、このプログラムに関する包括的な情報と、その使い方が提供されています。
- 「Eclipse Platform入門」は、Eclipseとプラグインのインストール方法を含めて、Eclipseの歴史と概要を解説しています
- Javaスキルを磨くために、developerWorksのJava technologyゾーンを見てください。
- developerWorksのOpen sourceゾーンをご覧ください。オープンソース技術を使った開発や、IBM製品でオープンソース技術を使用するためのハウ・ツー情報やツール、プロジェクトの更新情報など、豊富な情報が用意されています。
-
developerWorks technical events and webcastsを利用して、最新技術を身につけてください。
製品や技術を入手するために
-
WebSphere Application Server V6.0の無料試用版をダウンロードしてください。
- 皆さんの次期開発プロジェクトを、IBM trial softwareを使って構築してください。developerWorksから直接ダウンロードすることができます。
-
無料の2枚組DVDセット、SEK for Linuxをご注文ください。DB2®やLotus®、Rational®、Tivoli®、WebSphere® など、Linux用の最新IBMソフトウェア試用版が含まれています。
- 皆さんの次期オープンソース開発プロジェクトを、IBM trial softwareを使って革新してください。ダウンロード、あるいはDVDで入手することができます。
議論するために
-
developerWorks blogsに参加して、developerWorksコミュニティーに加わってください。
