内部クラスを使った方法
もう1つの、比較的よく用いられる方法は「内部クラス」と呼ばれるものを利用する方法です。内部クラスとは、文字通り「クラスの中に作成されたクラス」のことです。実は、クラスというのはどんな場所にも定義できるのです。
package codezine.java; import java.awt.event.*; import javax.swing.*; public class Sample extends JFrame { JLabel label; JTextField field; JButton button; public Sample(){ this.setSize(300,200); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLayout(null); // JLabelの組み込み String msg0 = "<html><h3>Sample</h3></html>"; label = new JLabel(msg0); label.setSize(200,30); label.setLocation(20,20); this.add(label); // JTextFieldの組み込み field = new JTextField(); field.setSize(200,20); field.setLocation(20,50); this.add(field); // JButtonの組み込み button = new JButton("JButton"); button.setSize(100,25); button.setLocation(20,80); button.addActionListener(new ActionAdapter()); this.add(button); } public static void main(String[] args) { Sample sample = new Sample(); sample.setVisible(true); } class ActionAdapter implements ActionListener { public void actionPerformed(ActionEvent ev){ String s = field.getText(); label.setText("あなたは、" + s + "と書きました。"); } } }
このリストを見てください。ActionAdapterクラスの定義が、Sampleクラスの中に書かれています。フィールドやメソッドと同じように、Sampleクラスの要素の1つとしてActionAdapterクラスが書かれています。こうすれば、ActionAdapterクラスはSampleクラスの要素の1つですから、同じSampleクラス内のlabelやfieldといったフィールドもそのまま利用できます。
また、ActionAdapterを利用するのがコンストラクタの中だけであれば、こんな書き方をすることもできます。
package codezine.java; import java.awt.event.*; import javax.swing.*; public class Sample extends JFrame { JLabel label; JTextField field; JButton button; public Sample(){ this.setSize(300,200); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLayout(null); // JLabelの組み込み String msg0 = "<html><h3>Sample</h3></html>"; label = new JLabel(msg0); label.setSize(200,30); label.setLocation(20,20); this.add(label); // JTextFieldの組み込み field = new JTextField(); field.setSize(200,20); field.setLocation(20,50); this.add(field); // JButtonの組み込み button = new JButton("JButton"); button.setSize(100,25); button.setLocation(20,80); class ActionAdapter implements ActionListener { public void actionPerformed(ActionEvent ev){ String s = field.getText(); label.setText("あなたは、" + s + "と書きました。"); } } button.addActionListener(new ActionAdapter()); this.add(button); } public static void main(String[] args) { Sample sample = new Sample(); sample.setVisible(true); } }
今度は、Sampleクラスのコンストラクタの中にActionAdapterクラスの定義が書かれています。こうすると、メソッドの中で宣言された変数などと同様に、そのメソッドの中(ここではコンストラクタ)だけでクラスが利用できるようになります。
内部クラスを使った方法は比較的分かりやすくイベントリスナーを用意できますし、一応、それぞれのイベントリスナーごとにまとめられますので、すべて1クラスに詰め込むよりは分かりやすく設計できるでしょう。
無名クラスを使った方法
これを更に突き進めると、addActionListenerの引数の()内にクラスの定義をいれてしまう、ということもできることが分かります。
package codezine.java; import java.awt.event.*; import javax.swing.*; public class Sample extends JFrame { JLabel label; JTextField field; JButton button; public Sample(){ this.setSize(300,200); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLayout(null); // JLabelの組み込み String msg0 = "<html><h3>Sample</h3></html>"; label = new JLabel(msg0); label.setSize(200,30); label.setLocation(20,20); this.add(label); // JTextFieldの組み込み field = new JTextField(); field.setSize(200,20); field.setLocation(20,50); this.add(field); // JButtonの組み込み button = new JButton("JButton"); button.setSize(100,25); button.setLocation(20,80); button.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ev){ String s = field.getText(); label.setText("あなたは、" + s + "と書きました。"); } }); this.add(button); } public static void main(String[] args) { Sample sample = new Sample(); sample.setVisible(true); } }
addActionListenerの引数に、new ActionListener(){……}という形で、ActionListener()の後にクラスの定義が書かれています。こうすることで、ActionListenerのインスタンスを作成する際にこれらの定義を組み込んだクラスが生成され、インスタンスを作成できるようになります。これが「無名クラス」と呼ばれるものです。
無名クラスは、処理の途中にいきなりクラス定義がはめ込まれるので、正直、かなり分かりにくいです。慣れるまでは、何がどうなってるのかよくわからないかも知れませんね。
また、その場でクラスとインスタンスが生成されるので、例えば「1つのインスタンスを複数のコンポーネントに組み込む」というようなことはできません。あまり複雑な処理を書くと無名クラスを組み込んでいるメソッドがやたらと長くなってしまうなど、弊害もあります。短い定型文程度の処理をイベントに組み込むような場合に限定的に使うもの、と考えた方がよいかもしれません。
まとめ
今回はアクションリスナーを例に、イベントリスナーの作成方法と、さまざまな組み込み方法について説明をしました。アクションリスナーの作成そのものはそれほど難しいものではありません。「implements」というものの書き方さえ分かれば、クラス自体は簡単に作れるはずです。問題は、それをメインクラスからどう利用するのがいいかというところでしょう。
また、アクションリスナーのさまざまな組み込み方も紹介しました。これらはすべてアクションリスナー以外のイベントリスナーでもそのまま利用できるものです。イベントリスナー組み込みの基本として、ここにあげた方法ぐらいは知識として身につけておきたいものです。
とはいえ、いきなり全部を覚えるのは難しいでしょう。特に無名クラスなどは、実際に自分で応用してみろといわれると考え込んでしまうかもしれません。まずは、Sample自身にimplementsして実装する方法から覚えていきましょう。これは、一番よく用いられる手法で、たいていの場合はこれで何とかなるものです。
ここにあげたものは、すべてわからないとイベント処理ができないというわけではありません。どれか1つを確実に使えるようになれば、それで済んでしまうことでしょう。まずは確実にアクションイベントの処理を書けるようになるのが先決。内部クラスや無名クラスによる方法は、その後でゆっくり学ぶ、と考えるとよいでしょう。
