の各ボタンを実装することにします。
テーブルの表示
それでは、Master(一覧)にテーブルを表示してみましょう。まず、FieldsBlockクラスのcreateMasterPart()メソッドで、セクションのタイトルと説明を変更します。次に確認のために配置したラベルとテキストボックスを削除し、テーブルを生成します。
ラベルやテキストボックスと同様にFormToolkitクラスのファクトリーメソッドcreateTable()を使用してテーブルを生成します。テーブルは行全体を一度に1行だけ選択できるようにするため、SWT.SINGLE, SWT.FULL_SELECTIONを指定します。それでは実行してみましょう。
Master(一覧)にテーブルが表示されました。しかし、マニフェストエディターのようにエディターの枠全体に広がっていません。どのようにすればテーブルを枠全体に広げることができるのでしょうか。
レイアウト
テーブルの表示サイズについて考える前に、ウィジェットの配置方法について考えてみましょう。SWT(Standard Widget Toolkit)を基盤としたUIコンポーネントの配置は設定されたレイアウトによって決まります。SWTでは標準的なレイアウトクラスとして下記の3つを提供しています。
FillLayoutクラス
もっともシンプルなレイアウトです。ウィジェットは垂直・水平いずれかの指定された方向に対して同じサイズで配置されます。使いやすい反面、ウィジェットのサイズが等分されるので、あまり見栄えのしないレイアウトになります。
RowLayoutクラス
FillLayoutクラスよりも一般的に使用されているのがRowLayoutクラスです。FillLayoutクラスと同じく、垂直または水平方向にウィジェットを配置していきますが、ウィジェットのサイズは等分されません。
GridLayoutクラス
GridLayoutクラスは標準的なレイアウトクラスの中で最も一般的に使われています。ウィジェットをグリッド(格子)上に配置していくことができるため、柔軟な配置を行うことができます。
子を保持できるウィジェット(Compositeクラスを継承したウィジェット)に対してレイアウトを設定することで、ウィジェットの配置を制御することができます。なお、SWTのレイアウトについては、Eclipse Corner Articleの「Understanding Layouts in SWT」に詳しく説明されていますので、ご参照ください。
Master(一覧)のレイアウト
レイアウトについてひととおり学んだところで、Master(一覧)のレイアウトを考えてみましょう。まず採用するレイアウトですが、 GridLayoutクラスが一般的かつ柔軟だということなので、全面的にこれを採用することにします。テーブルとボタン群にそれぞれ1列ずつ割り振り、ボタン群に対しては別途Compositeクラスを用意してそこに各ボタンを配置することにします。
GridDataオブジェクトの設定
GridLayoutはレイアウト時に各ウィジェットからGridDataオブジェクトを取得し、その設定情報に基づいて配置方法を決定します。従って、適切に設定したGridDataオブジェクトをTableオブジェクトに設定すれば、テーブルを枠全体に広げて表示することができます。GridDataオブジェクトに対してどのような設定が可能か見てみましょう。
フィールド名 | 説明 |
exclude | ウィジェットが保持するサイズと位置情報を無視するか |
grabExcessHorizontalSpace | ウィジェットが配置されるセルの幅を親コンポジットに合わせるか |
grabExcessVerticalSpace | ウィジェットが配置されるセルの高さを親コンポジットに合わせるか |
minimumHeight | ウィジェットが配置されるセルの最小の高さを指定する |
minimumWidth | ウィジェットが配置されるセルの最小の幅を指定する |
horizontalAlignment | セル内での水平方向の配置方法を決定する。設定は左寄せ(SWT.BEGINNING(LEFT))、中央寄せ(SWT.CENTER)、右寄せ(SWT.END(RIGHT))、あるいは全体に広げる(SWT.FILL)のいずれかから選択可能です |
verticalAlignment | セル内での垂直方向の配置方法を決定する。設定は左寄せ(SWT.BEGINNING(TOP))、中央寄せ(SWT.CENTER)、右寄せ(SWT.END(BOTTO
))、あるいは全体に広げる(SWT.FILL)のいずれかから選択可能です |
horizontalIndent | セルの左端からの水平方向のインデント位置を設定する |
verticalIndent | セルの上端からの垂直方向のインデント位置を設定する |
horizontalSpan | 水平方向に結合するセル数を指定する |
verticalSpan | 垂直方向に結合するセル数を指定する |
heightHint | ウィジェットの最適な高さを指定する |
widthHint | ウィジェットの最適な幅を指定する |
テーブルを枠全体に広げるには、まずウィジェットが配置されるセルのサイズを親コンポジットの枠全体に広げ、次にテーブル自体をセルの枠全体に広げます。これを水平・垂直方向に対して行います。
それでは実行してみましょう。テーブルを枠全体に広げることができました。
Fieldクラスの作成と一覧表示
テーブルを表示することができましたので、次は表示するデータを考えてみます。まずテーブルに1行ずつ表示するデータはフィールドの情報なので、それを保持するクラスを作成しましょう。
Fieldクラスはフィールド名、説明、必須かどうか、メッセージの各プロパティーを持ち、それらのgetter/setterメソッドを提供するクラスです。続いて、FieldsPageクラスでサンプルデータを作成し、表示してみます。
それでは実行してみましょう。作成したサンプルデータが一覧表示されます。
TableViewerクラスの導入
前項の方法は作成したサンプルデータを表示するために、TableItemクラスを使って1行ずつデータを文字列として設定するというものでした。しかし、この方法はすぐに破綻しそうです。というのも、Tableオブジェクトはフィールド名と説明を文字列として保持しているだけなので、詳細を表示するときにほかのデータを表示することができません。テーブルのデータと同じ内容のListオブジェクトを保持するなど、工夫次第では実装できないことはないですが、明らかに複雑になります。
この問題を解決するために、JFaceのTableViewerクラスを導入します。JFaceについては、ヘルプの「Platform Plug-in Developer Guide」→「Programmer's Guide」→「The JFace UI framework」に概要が記されています。それによるとJFaceはUIプログラミングにおいて共通する処理をまとめたヘルパークラスを提供しています。今回のように「ウィジェット(Table)とモデル(Field)の関係」をまとめる機構として、JFaceではビューアーを提供しています。ビューアーが間に入ることでFieldオブジェクトのデータを直接テーブルに追加するといった処理が不要になります。また、データをモデルクラスの形式でやりとりできるので、追加や削除も簡単に行えます。今回はTableクラスのビューアーであるTableViewerクラスを使用します。
コンテンツプロバイダーとラベルプロバイダー
ウィジェットとモデルの仲介を行うビューアーですが、実際の仲介処理はコンテンツプロバイダーとラベルプロバイダーに委譲しています。コンテンツプロバイダーはビューアーからの要求に対して適切な形式でモデルを返します。独自に実装することも可能ですが、一般的にJFaceが提供しているコンテンツプロバイダーを使用します。今回は指定されたエレメントを配列で返すArrayContentProviderクラスを使用します。
ラベルプロバイダーはモデルをどのように表示するかを決定します。例えば、今回であれば1列目にフィールド名、2列目に説明を表示しています。これを指定するのがラベルプロバイダーです。従って、ラベルプロバイダーは独自に実装する必要があります。今回はTableViewerクラスのためのITableLabelViewerインタフェースを実装します。
コンテンツプロバイダーにはArrayContentProviderオブジェクトをセットします。ラベルプロバイダーにはITableLabelProviderインタフェースを無名クラスで実装します。いくつかメソッドがありますが、今のところ実装するのはgetColumnText()メソッドのみです。このメソッドでは列にセットする文字列を返すために、1列目の場合はフィールド名、2列目の場合は説明をそれぞれ返すようにしています。それでは実行してみましょう。サンプルのデータが表示されれば成功です。
ビューアーを導入することで、テーブルを直接操作してFieldオブジェクトをセットしているコードがなくなっているのがわかります。
おわりに
今回はレイアウトとビューアーについて説明しました。SWT/JFaceの話が中心になりましたが、Eclipse FormsがSWT/JFaceの上に成り立っているものであることがよくわかります。
次回はMaster(一覧)のボタン部分とDetails(詳細)の入力項目定義フォームを実装します。