JButtonをクリックをした時に実行させるプログラムは、どこに書けばよいのでようか?
実は、クリックの時に呼び出す命令(メソッド名)が決まっているのです。
それは、ActionListenerという名前のインターフェイス(interface)内の
actionPerformedという名前のメソッドです。
interfaceは、メソッドの宣言だけを行う特別なクラスのようなものです。
ですが宣言があれば、その「宣言のメソッド」を呼び出しするコードが書ける規則があります。
JButton内部では、この規則を利用して、actionPerformedを
呼び出す記述があるのです。
(宣言だけのメソッドは、C言語のプロトタイプ宣言に似ています。
宣言だけなので最終的には、宣言の実体となるメソッドを作らなければ、リンクした作品を作ることはできません。
しかし、コンパイルまでは可能ということです。)
JButtonを利用する側では、そのクリック操作の処理を、
このactionPerformedメソッド宣言の実体を書けばよいことになります。
このinterfaceのメソッドの実体を作る場合は、そのメソッドを作るクラス定義で、
implementsキーワードを使い「interfaceの名前」を指定します。
implementsキーワードで、インターフェイスのメソッドを実装するクラスは何でも構いません。
以下でTestFrm02の派生クラスとしてTestFrm03クラスを作成し、このTestFrm03に
ActionListenerインターフェイスの
actionPerformedを実装(implements)する例を
示します。
このactionPerformedメソッドを、
TestFrm02クラスにあるJButtonオブジェクトのクリック処理にするわけです。
TestFrm02クラスは、前ページで作成したもので、すでに存在する状態で作ります。
(そのクラス図も示します。インターフェイスは、○で表現することができます)
package test; import java.awt.event.ActionListener;//クリック用のインターフェイス import java.awt.event.ActionEvent;//イベント情報(クリックイベントなど)クラス import javax.swing.JButton; public class TestFrm03 extends TestFrm02 implements ActionListener { public TestFrm03(){ this.btn1.addActionListener( this ); this.btn2.addActionListener( this ); this.btn3.addActionListener( this ); } public void actionPerformed(ActionEvent e){ JButton btn = null; if (e.getSource() instanceof JButton){ btn = (JButton)e.getSource();//クリックしたオブジェクト取得 btn.setVisible(false);//見えなくする。 } if (btn == this.btn1){//クリックしたオブジェクトが、btn1か? this.btn2.setVisible(true); //見えるようにする。 }else{ this.btn1.setVisible(true); } } public static void main(String[] args){ new TestFrm03(); } }
なおJButtonのオブジェクトに、
どのオブジェクトのactionPerformedメソッドを、
クリック処理に使うか指定する必要があります。
(JButtonは、そのクリックでactionPerformedを実行するよう作られていますが、どのオブジェクトのactionPerformedを実行させるかは、後で指定するようになっているのです。)
そのための指定が、addActionListenerメソッドで、
この引数にactionPerformedメソッドを実装したオブジェクトを指定します
ここでは、TestFrm03クラスに実装したので、そのオブジェクトの this を渡しています。
ここでは、btn1、btn2、btn3 に
.addActionListener( this );の
設定を行っているので、この3つボタンだけが、
クリックすると actionPerformedメソッドを実行します。
では、どのボタンがクリックされたのかをどのように判断すればよいのでようか?
それは、actionPerformedメソッドの引数 ActionEvent eで
判断できます。
このオブジェクトから、e.getSource()でクリックしたオブジェクトを取得できます。
それに対し、instanceof演算子で どのクラスの派生クラスかを調べることができます。
e.getSource()の戻り値はObject型なので、JButtonにキャストして、
JButtonの変数に参照し直せば、その変数でクリックしたJButtonへの操作が可能となります。
上記では、クリックしたオブジェクトがJButton派生クラスのオブジェクトであれば、
ローカル変数btnに参照し直して、その表示を消しています。
また、そのオブジェクトがbtn1であれば、btn2を表示状態に変更し、そうでなければbtn1を表示しています。
(btn3, btn2, btn1の順番でクリックすると分かりやすいでしょう)
さて、interfaceのメソッドの実体を作る場合は、そのメソッドを作るクラス定義で、
implementsキーワードを使い「interfaceの名前」を指定します。
その時点で、
そのインターフェイスで宣言されたメソッドの実体を実装しなければならない規則が適用されます。
(interfaceのメソッドを実装しなければオブジェクト生成もできません)
つまり、ActionListenerをimplementsした時点で、
actionPerformedを、ActionListener内の宣言通りに
作らないとエラーになります。
ActionListenerインターフェイスのソースを見ると次のようになっています。
(JDK1.6内のsrc.zip内のjava/awt/event/ActionListener.javaのソースです)
public interface ActionListener extends EventListener {
public void actionPerformed(ActionEvent e);
}
上記の が宣言部分です。この通りの メソッドを実装しなければなりませんが、例えばTestFrm03クラス定義で、うっかり actionPerformedをスペルミスしてactionerformedでを作ると、次のエラーが指摘されます。
D:\java>javac test\TestFrm03.java test\TestFrm03.java:6: test.TestFrm03 は abstract でなく、java.awt.event.ActionL istener 内の abstract メソッド actionPerformed(java.awt.event.ActionEvent) をオ ーバーライドしません。 public class TestFrm03 extends TestFrm02 implements ActionListener ^ エラー 1 個 D:\java>
Javaでは宣言だけで実体がないメソッドを abstract メソッドと呼びます。
上記エラーメッセージのabstract メソッドは、
ActionListenerインターフェイスのactionPerformedメソッドのことです。
ActionListenerインターフェイスをimplements(実装)するということは、
ActionListenerインターフェイスの機能を引き継ぎ、宣言のメソッドを、
実体に作り直すオーバーライドをしなければならない指定です。
そして、そのオーバーライドがなされていないというエラーメッセージです。
補足 TestFrm03クラス定義の先頭が次のようになっています。
class TestFrm03 extends TestFrm02 implements ActionListener
これは次の意味です。
extendsキーワードでTestFrm02を継承し、TestFrm03を作っています。
そして同様に、
implementsキーワードでActionListenerを継承し、TestFrm03を作っています。
つまり、extends、implementsキーワード共に、継承したクラスを
作るという指定です。
実際、このように作ったオブジェクトは、その継承元の型の変数で、
次のように参照することができます。
TestFrm02 f1 = new TestFrm03(); //f1で管理
ActionListener f2 = new TestFrm03();//f2で管理
では、extends と implementsの違いは何でしょうか?
extendsの後にクラスまたはインターフェイスを指定できますが、指定できるのは一つだけです。
またその時に、継承元クラスにあるabstract メソッドを
作らなければならないという規則はありません。
対して、implementsで指定するのはインターフェイス名でなければなりません。
そして、指定したインターフェイスのabstract メソッド(宣言)は全て実体を
作らなくてはならない規則になっています。