GUIアプリケーションは、ユーザが行ったアクションを、 イベントとしてそれを適切に処理するプロシージャ(関数・メソッド)に送ることによって 動作する、イベントドリブン方式のプログラムです。
+----------+ action +---------+ event +----------+ | ユーザー |------->| control |------>| listener | +----------+ +---------+ +----------+SWTにおけるGUIプログラミングも、これの例外ではありません。
SWTでは、org.eclipse.swt.eventパッケージを使用して、イベントドリブン方式のプログラミングを実現することができます。
最もシンプルなイベントは、「ボタンが押された」というイベントです。 このイベントは、SelectionEventクラスで表されます。 そしてselectionEventを受け取るのは、SelectionListenerインターフェイスを実装したクラスです。 SelectionListenerインターフェイスには、2つのメソッドが定義されていますが、 ボタンの場合は、widgetSelected(SelectionEvent)メソッドのみしか呼び出されません。
そして作成したSelectionListener実装クラスは、 Button#addSelectionListener(SelectionListener)でセットすることができます。
SelectionListener実装クラスのサンプルです。 今回の実装では、Labelインスタンスを引数にとって、 イベントを受け取る度にカウントを1ずつ増やしてラベルに書き出すという処理を行います。
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Label;
public class MySelectionListener implements SelectionListener {
private Label label;
private int count = 0;
public MySelectionListener(Label label) {
this.label = label;
}
public void widgetDefaultSelected(SelectionEvent e) {
// 呼び出されないので処理は記述しない
}
public void widgetSelected(SelectionEvent e) {
label.setText("count : " + Integer.toString(++count));
}
}
作成したMySelectionListenerクラスは、Button#addSelectionListener(SelectionListener)により登録します。
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
public class EventDemonstrate extends ApplicationWindow {
private EventDemonstrate() {
super(null);
}
protected Control createContents(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
Button button = new Button(composite, SWT.NONE);
button.setText("count");
button.setLocation(5, 5);
button.pack();
Label label = new Label(composite, SWT.NONE);
label.setText("default");
label.setBounds(5, 50, 150, 25);
// buttonにMySelectionListenerを登録
button.addSelectionListener(new MySelectionListener(label));
composite.pack();
parent.pack();
return parent;
}
public static void main(String[] args) {
Window w = new EventDemonstrate();
w.setBlockOnOpen(true);
w.open();
Display.getCurrent().dispose();
}
}

このように、SelectionListenerは、controlに単純なイベントが発生した場合に呼び出されます。 SelectionListenerを登録できるcontrolには、addSelectionListenerメソッドが定義されていますので、 個々のcontrolのAPIを参考にして、SelectionListenerを登録できるかどうかを調べることができます。
すべてのイベントクラスは、TypedEventクラスを親に持ちます。 このTypedEventオブジェクトには、そのイベントの発生元の情報が記載されています。
SelectionEventクラスもやはりTypedEventクラスを親に持つので、 TypedEventのフィールド値に直接アクセスすることができます。
TypedEventのフィールドを有効的に使用するサンプルを示します。
import java.util.HashMap;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Button;
public class MyButtonCountingListener implements SelectionListener {
HashMap<Button, Short> buttonCounts = new HashMap<Button, Short>();
public MyButtonCountingListener() {
}
public void widgetDefaultSelected(SelectionEvent e) {
// 呼び出されないので処理は記述しない
}
public void widgetSelected(SelectionEvent e) {
// イベント発生元のbuttonを取得
Button selectedButton = ((Button)e.widget);
Short count = buttonCounts.get(selectedButton);
// buttonが登録されていなかったら、countを0で初期化する
if (count == null) {
count = (short)0;
}
count++;
selectedButton.setText(Short.toString(count));
// buttonを現在のcountで登録
buttonCounts.put(selectedButton, count);
}
}
MyButtonCountingListenerクラスは、イベントが呼び出されると、
TypedEventのフィールドからイベント発生元のbuttonを取得し、
あらかじめbuttonCountsマップに登録しておいたbuttonからカウントを取得し、インクリメントして
ボタンのテキストにセットします(もしも登録されていなかった場合はcountを0で初期化しています)。
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
public class EventDemonstrate2 extends ApplicationWindow {
private EventDemonstrate2() {
super(null);
}
protected Control createContents(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
int x = 5;
Button button1 = new Button(composite, SWT.PUSH);
button1.setText("button1");
button1.setBounds(x, 5, 55, 30);
Button button2 = new Button(composite, SWT.PUSH);
button2.setText("button2");
button2.setBounds(x += 60, 5, 55, 30);
Button button3 = new Button(composite, SWT.PUSH);
button3.setText("button3");
button3.setBounds(x += 60, 5, 55, 30);
MyButtonCountingListener buttonCountingListener =
new MyButtonCountingListener();
// buttonにMySelectionListenerを登録
button1.addSelectionListener(buttonCountingListener);
button2.addSelectionListener(buttonCountingListener);
button3.addSelectionListener(buttonCountingListener);
composite.pack();
parent.pack();
return parent;
}
public static void main(String[] args) {
Window w = new EventDemonstrate2();
w.setBlockOnOpen(true);
w.open();
Display.getCurrent().dispose();
}
}
MyButtonCountingListenerを使用するプログラムです。

SelectionAdapterクラスは、SelectionListenerインターフェイスの実装クラスです。 つまりwidgetDefaultSelectedメソッドとwidgetSelectedメソッドを実装しています。 しかし、どちらのメソッドも、何も行わない、空の処理です。
どうしてこのようなクラスが定義されているかというと、 先ほどまでのサンプルプログラムで書いてきた、widgetDefaultSelectedメソッドのような、 使わないのにインターフェイスの実装のためにわざざわ書かなければいけないメソッドを あらかじめ実装しておくことで、コーディングに要する時間を短縮 しようという意図があります。
サンプルプログラムで示した、MyButtonCountingListenerを、SelectionListenerインターフェイスを実装してではなく、 SelectionAdapterクラスを継承した形で記述すると、次のようになります。 widgetDefaultSelectedメソッドの記述が省略されています。
import java.util.HashMap;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
public class MyButtonCountingListener extends SelectionAdapter {
HashMap<Button, Short> buttonCounts = new HashMap<Button, Short>();
public MyButtonCountingListener() {
}
public void widgetSelected(SelectionEvent e) {
// イベント発生元のbuttonを取得
Button selectedButton = ((Button)e.widget);
Short count = buttonCounts.get(selectedButton);
// buttonが登録されていなかったら、countを0で初期化する
if (count == null) {
count = (short)0;
}
count++;
selectedButton.setText(Short.toString(count));
// buttonを現在のcountで登録
buttonCounts.put(selectedButton, count);
}
}
SelectionListenerがよく使われますが、その他にもいろいろな場面でいろいろなリスナを 適切に使い分けてプログラミングを行う必要があります。
例えば、タイピングゲームやテキストエリアを使用する場合には、KeyListenerを使います。 お絵かきソフト等のような、マウスの操作をユーザに求めるプログラムでは、MouseListenerを使います。 そしてそれぞれのListenerのメソッドには、それぞれに対応したEventが呼び出されます。