レベル: 中級 米持 幸寿, テクノロジー・エバンジェリスト, IBM
2007年 06月 20日
JVEを利用していると、「自分のコンポーネントもJVEできちんと使いたい」と思うようになります。自分で作成したコンポーネントを共通部品のような形で再利用し、ビジュアル・エディターの上で活用するには、ツールそのものを拡張していく必要があります。今回から、JVEを拡張(改造)して、独自コンポーネントをビジュアルエディターに統合する方法を紹介していきます。
調整が必要なプロパティーとは?
簡単なところで、プロパティー・エディターの調整をしてみましょう。プロパティー・エディターの調整が必要なケースは、選択オプションのためのフラグを持たせるような場合です。
今回は、題材として入力値を検査してくれるテキスト入力フィールドを作りましょう。Composite
を継承したVisual
Classを作り、レイアウトをFillLayoutにして、テキストフィールドを一つ追加します。int型で「option」フィールドを作り、その値として、staticfinal
値を四つ定義しましょう。optionフィールドには0から3での4種類の数値がセットでき、0:汎用、1:数字、2:半角英文字、3:全角という意味になるようにします。getter、setterも準備します。
public static final int NONE = 0; // 汎用
public static final int NUMERIC = 1; // 数字
public static final int ALPHA = 2; // 半角英字
public static final int KANJI = 3; // 全角
private int option = NONE;
oublic int getOption() { return this.option; }
public void setOption(int option) { this.option = option; }
|
このオプションを見ながら、キーイベントを拾って中身を検査し、フィールドを赤くするようなコードを作ることにします。たとえば、以下のようなリスナーをテキストフィールドに実装することで、打ち込まれた内容が条件に合わないと赤くなるテキストフィールドを作ることができます。(テキストフィールドを右クリックして、メニューから「Events」→「modifyText」で、このコードを書き込みます)
text.addModifyListener(new org.eclipse.swt.events.ModifyListener() {
public void modifyText(org.eclipse.swt.events.ModifyEvent e) {
boolean error = false;
switch(option){
case NUMERIC:
try{
Integer.valueOf(text.getText());
} catch(Exception exp){
error = true;
}
break;
case ALPHA:{
String str = text.getText();
byte[] bytes = str.getBytes();
if(str.length() != bytes.length) {
error = true;
}
break;}
case KANJI:{
String str = text.getText();
byte[] bytes = str.getBytes();
if(str.length()*2 != bytes.length) {
error = true;
}
break;}
default:
}
if(error){
text.setBackground(getDisplay().getSystemColor(SWT.COLOR_RED));
} else {
text.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
}
}
});
|
別のコンポジットを作って、その上にドラッグ&ドロップして実行してみると、図1.のようになります。
図1.実行結果
このような方法はJavaではとてもポピュラーな方法ですが、プロパティー・エディターを見ると、図2のように表示されてしまいます。
図2.数値を入力するフィールド
この状態だと、ビジュアル・エディターで画面を定義する作業者は、0、1、2、3の意味を知っていて、数値で入力せざるを得ません。また、間違えて「A」と入力できてしまいます。
ここに、「汎用」「数値用」「半角英字用」「漢字用」といったように、わかりやすいラベルで選択肢が表示されるようにする方法を紹介します。
JavaBeans仕様
Visual Editor で作成している Composite は、Javaの基本仕様から見ると
JavaBeans
です。JVEは、JavaBeans仕様のイントロスペクションやリフレクションという機能を使って、コンポーネントの特徴(プロパティー、メソッド、イベント)などを調べ、エディター上に表現しています。JavaBeansのプロパティーがどのようなものかを意図的にJVEに伝えるためには、JavaBeans仕様で決められている
BeanInfo
を利用します。
JavaBeansといえば、今日では、Webアプリケーションのデータオブジェクトやサービス実装のためのコンポーネント仕様の一つのように考えられていますが、もとはといえばGUIコンポーネントをビジュアルツール(ビルダーと言います)で編集するための仕様として作られた技術です。ですから、JVEとも密接な関係にあります。
JavaBeansは、完成したプログラム(ここではビルダツール、つまりJVEを意味しています)に、あとから外部の完成したプログラム(部品、つまりComposite)を認識させるための技術と考えてください。たとえば、あなたが「MyButton」という部品を作ったとき、プログラムがその部品を自分でnewすることは難しいと思います。なぜなら、MyBeanをソースコードに書き込む必要があり、「MyBean」というデータをからnewすることができないからです。(コード1)
MyBean mb = new MyBean();
|
このように、newによって部品を認識させるためには、ビルダー・ツールのソースコードを編集してコンパイルしなければならなくなります。そうせずに、文字列のデータとしてクラス名を渡し、そのクラスを取り扱うための仕組みを提供するのがJavaBeans仕様です。ビルダーツールは、当然、そのクラスにどのようなプロパティがあり、どのようなメソッドがあるかを「あとから」知る必要があります。ここでいう「あとから」とは、コンパイルが終わったあと、という意味です。
「JavaBeans」という単語は仕様、あるいはアーキテクチャーの名前です。JavaBeansアーキテクチャーのなかで部品は「bean」と呼びます。beanには、「プロパティー」「メソッド」「イベント」という機能があり、それらによって、他のbeanと結合されていく、というコンセプトです。
JavaBeans仕様では、以下の機能を定義して、beanをビルダーツールに組み込むことができます。
| イントロスペクション | ビルダーツールが、beanの機能を読み取ること | | Introspector | このクラスが、beanの機能へのアクセスを可能にする | | リフレクションAPI |
オブジェクトの認識、クラス情報の取得、インターフェース情報の取得、インスタンス化、文字列データによるプロパティ名やメソッド名へのアクセス、呼び出し、配列の生成などを行うAPI
| | BeanInfo | 特定のクラスのプロパティー、メソッド、イベントに関する情報を提供するために使う | | カスタマイゼーション | プロパティー・エディター、beanカスタマイザーのいずれかで、編集するための仕組み | | パーシスタンス |
beanをファイルに保存したり、ネットワークへ送信するためにバイト配列に変換する仕組み。Serializationインターフェースの実装による。
|
この仕組みが、データを取り扱うときにも役に立つため、Webアプリケーションのデータオブジェクトに幅広く使われているわけです。
JavaBeans仕様には多くの機能が定義されていますが、多くはビルダー実現のためのものです。ここでは、自作のコンポーネントをビルダー、つまりJVEに認識させるための仕様であるBeanInfoを中心に解説し、プロパティー・エディターの表示方法を調整する方法を説明していきます。
BeanInfoを準備
BeanInfo
は、作成した部品名+BeanInfoという名称のクラスを作り、java.beans.BeanInfoインターフェースを実装することで準備します。クラスパスが通っていれば、そのBeanInfoが使われます。
たとえば、先ほど準備したComposite継承クラスに「ValidatableText」という名前を付けたとします。この場合、対応するBeanInfoクラスは「ValidatableTextBeanInfo」となります。
BeanInfoインターフェースを持つ「SimpleBeanInfo」クラスを継承するか、BeanInfoインターフェースを実装したクラスを準備します。ここでは、BeanInfoインターフェースを実装したクラスで説明していきます。
-
これまでの連載を参考に、Compositeにテキストフィールドが一つだけ乗っかっており、プロパティーとしてoptionを持ち、static
finalで、NONE、NUMERIC、ALPHA、KANJI
を持つコンポーネントを作ってください。(名前は ValidatableTextクラスとします)
-
部品を作ったのと同じパッケージのコンテキストメニューで「新規」→「クラス」で「ValidatableTextBeanInfo」クラスを選択してください。
-
ウィザードで、インターフェースにBeanInfoを追加し、作成するメソッドスタブの選択に「継承された抽象メソッド」が選択されていることを確認して、「終了」ボタンをクリックしてください。
-
getEventSetDescriptors()、および getMethodDescriptors()
にのみ、ゼロ個の配列を返すコードを書き込んでください。nullを返すと、NullPointerExceptionが原因で、このクラスが使われません。
BeanInfoクラスのうち、getPropertyDescriptors
メソッドが、プロパティー・エディターに影響します。まずは試しにゼロ個の配列を返すコードを書き込んで認識させてみましょう。
package com.yone.swt.components;
import java.awt.Image;
import java.beans.BeanDescriptor;
import java.beans.BeanInfo;
import java.beans.EventSetDescriptor;
import java.beans.IntrospectionException;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
public class ValidatableTextBeanInfo implements BeanInfo {
Class beanClass = ValidatableText.class;
public PropertyDescriptor[] getPropertyDescriptors() {
return new PropertyDescriptor[0];
}
public BeanInfo[] getAdditionalBeanInfo() {
return null;
}
public BeanDescriptor getBeanDescriptor() {
return null;
}
public int getDefaultEventIndex() {
return 0;
}
public int getDefaultPropertyIndex() {
return 0;
}
public EventSetDescriptor[] getEventSetDescriptors() {
return new EventSetDescriptor[0];
}
public Image getIcon(int iconKind) {
return null;
}
public MethodDescriptor[] getMethodDescriptors() {
return new MethodDescriptor[0];
}
}
|
このクラスができたら、ビジュアル・エディターのキャッシュをフラッシュするために、メニュー・から「プロジェクト」→「クリーン」を実行してください。
この状態で、新しく Visual
Class(Compositeを継承)を作り、ValidatableTextをパレットの「Choose
Bean」から選択して、ドロップしたあと、プロパティー・エディターを見てみてください。
図3.PropertyDescriptorゼロ個の状態
図3.のようになったでしょうか?うまくいかないときは、テストクラスを作ってmainメソッドで、java.beans.Introspector.getBeanInfo(ValidatableText.class);を実行して、例外などが発生してないか確認しましょう。
ずいぶん、少ないような気がしますね。これは、BeanInfoクラスがPropertyDescriptorゼロ個を返すために、プロパティー・エディターが認識できるプロパティーが減ってしまったためです。これで、BeanInfoがJVEによって呼ばれていることが確認できました。
PropertyDescriptorを作る
では、次に、optionフィールドには、四つの値が選択できることを示すためのPropertyDescriptorを作りましょう。
BeanInfoの中では、対象となるBeanのClassオブジェクトをよく使いますので、クラス変数として持たせておきます。
Class beanClass = ValidatableText.class;
|
リストxのコードを「getPropertyDescriptors」メソッドに書き込みます。
リスト1.getPropertyDescriptors メソッド
PropertyDescriptor[] result = null;
try {
PropertyDescriptor pd1 = new PropertyDescriptor(
"option",
beanClass
);
pd1.setValue(
"enumerationValues",
new Object[]{
"汎用",
new Integer(ValidatableText.NONE),
"com.yone.swt.components.ValidatableText.NONE",
"数字用",
new Integer(ValidatableText.NUMERIC),
"com.yone.swt.components.ValidatableText.NUMERIC",
"半角英字用",
new Integer(ValidatableText.ALPHA),
"com.yone.swt.components.ValidatableText.ALPHA",
"漢字用",
new Integer(ValidatableText.KANJI),
"com.yone.swt.components.ValidatableText.KANJI",
}
);
result = new PropertyDescriptor[]{
pd1
};
} catch (IntrospectionException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
result = new PropertyDescriptor[0];
}
return result;
|
PropertyDescriptorは、プロパティー名と、対象となるClassオブジェクトから作ります。PropertyDescriptorオブジェクトのsetValueメソッドによって、動作を変えていきます。今回は、int変数にいくつかの代入できる候補があるパターンで、これは「enumerationValues」と呼ばれています。文字列一つとObject配列でその候補を渡します。これらの詳細は、JavaBeansの資料に掲載されています。
このObject配列には並べ方に決まりがあります。それは、「表示名」「数値」「ソースコード上の表記」です。この三つの組み合わせで、候補の数だけ繰り返して代入された形とします。
PropertyDescriptorオブジェクトが準備できたら、それ自体を配列にいれてreturnします。
では、この状態でビジュアルエディターを見ましょう。先ほどビジュアル・エディターで開いてしまっている場合は一旦閉じてプロジェクトをクリーンした後、もう一度開いてプロパティー・エディターを見てください。
図4.プロパティーの表示が変わった
他にもプロパティーがある場合(プロパティー・エディター上に表示してほしい場合)は、PropertyDescriptorをその分用意し、配列に入れて返します。
著者について  | |  | 1987年に日本アイ・ビー・エム入社。メインフレームOS、ミドルウェアの障害対応、障害解析ソフトウェアの開発、ワークフローシステム開発、オブジェクト指向開発、Web開発など経験。2000年より、ソフトウェアのテクノロジーエバンジェリストとして活動中。 |
記事の評価
|