KeyListener、イベント処理の再利用

前ページの作品に、次の機能を追加します。
txt1テキストフィールドを空にするとボタンが、 JListの選択項目の削除用ボタンに変化して、 それをクリックするとその時選択状態になっているリスト内の項目を削除します。
txt1テキストフィールドが空でないと時の ボタンは、これまで同じJListへの追加ボタンにします。
この機能追加は、前作品のクラスTestFrm042を継承したTestFrm043のクラスに作成します。
テキストフィールドをキー操作(Back Spaceなど)で削除し、実験ください

テキストフィールドに対して操作が行なわれた時に、 テキストフィールドが空でないかを調べればよいでしょう。
そしてテキストフィールドのキー操作を絶えず調べるには、 java.awt.eventパッケージの KeyListenerインターフェイスを実装する必要があります。
このインターフェイスには、キー操作関連で次の3つのメソッドが宣言されています。

public interface KeyListener extends EventListener {

	public void keyPressed(KeyEvent e);//キーを押しているときに呼び出されます。
    
	public void keyTyped(KeyEvent e);//キーをタイプすると呼び出されます。

	public void keyReleased(KeyEvent e);//キーを離したときに呼び出されます。 
}

そして、これらメソッドの引数のKeyEvent eから、 その時のキー操作の情報が得られます。 文字としてキー情報が得たい場合は、e.getKeyChar()を使い、 コード番号としてキー情報が得たい場合は、 e.getKeyChar()を使います。 このKeyEventクラスの機能の調べてみましょう。

KeyListenerインターフェイスも java.awt.Componentクラスへのインターフェイスとして作られています。
java.lang.Object
  └java.awt.Component
    └java.awt.Container
      └javax.swing.JComponent
        └javax.swing.text.JTextComponent
          └javax.swing.JTextArea
よってJTextAreaクラスオブジェクトに対して、 これらキー操作を行うと、このインターフェイスのメソッドを 呼び出すように作れます。
あとは、KeyListenerインターフェイスを適宜なクラスに実装(implements)して、 そのオブジェクトのメソッドがキー操作呼び出されるようにJListへ設定するだけです。
ActionListenerの設定は、addActionListenerを使いました。
MouseListenerの設定は、addMouseListenerを使いました。
そしてKeyListenerの設定は、addKeyListenerを使います。
以下は、TestFrm042クラスで使えるtxt1フィールドの KeyListenerインターフェイス実装を、 そのサブクラスのTestFrm043に作るスケルトンコードです。 ■■■■の部分を正しく直しましょう。

←正しく修正してからクリックください。

←わからない場合は、クリック

あとは、このスケルトンコードに希望の処理を肉付けすればよいことになります。 以下で、冒頭目標のプログラムを示します。

package test;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
public class TestFrm043 extends TestFrm042 implements KeyListener, ActionListener
{
	public TestFrm043()	{
		this.btn1.removeActionListener(this);//これまでのActionListenerを削除
		this.btn1.addActionListener(this);//改めてこのオブジェクトを登録
		this.txt1.addKeyListener(this);
	}
	public void actionPerformed(ActionEvent e){
		if (this.btn1.getText().equals("削除") == false){
			super.actionPerformed(e)//追加処理
		} else {
			int idx = this.lst1.getSelectedIndex();//リスト選択位置取得
			if (idx != -1){//選択されている?
				this.listModel.remove( idx );//削除
			}
		}
	}
	public void keyPressed(KeyEvent e){//キーを押しているときに呼び出されます。
		System.out.println(this.txt1.getText() + ":Press=" + e.getKeyCode());
	}
	public void keyReleased(KeyEvent e)	{//キーを離したときに呼び出されます。 
		System.out.println(this.txt1.getText() + ":Released=" + e.getKeyCode());
		if (this.txt1.getText().equals("")) {
			this.btn1.setText("削除");
		} else {
			this.btn1.setText("追加");
			if (e.getKeyCode() == 10) {//Enterが押されたたか?
				this.actionPerformed(null);
			}
		}
	}
	public void keyTyped(KeyEvent e) {//キーをタイプすると呼び出されます。
		System.out.println(this.txt1.getText() + ":Typed=" + e.getKeyChar());
	}
	public static void main(String[] args) {
		new TestFrm043();
	}
}

上記において、テキストエリア(JTextArea)でキー入力した時に、 各メソッドが呼ばれます。 しかし、使っているのはキーが押し終わった時keyReleasedメソッドだけで、 基本的に、キー入力後のテキストフィールドの内容で、 空になったらボタンbtn1の表示内容を、 『削除』、そうでないなら『追加』の表示に変更しています。 そして押されたキー情報が改行(10のコード番号)なら、 this.actionPerformed(null);の実行で、リストへの追加を行っています。


extendsで指定する継承元クラスは1つだけしかできませんが、implementsで指定するインターフェイスは コンマで区切り複数指定できます。
上記ではimplements KeyListener, ActionListenerと ActionListenerインターフェイスも実装し、btn1ボタンのクリック処理用として actionPerformedメソッドをオーバーライドしています。
そこでは、btn1ボタンの表示内容が『削除』でないなら、super.actionPerformed(e) を実行し、そうでないなら、this.lst1.getSelectedIndex()でリストの選択項目の添え字を取得し、 その項目を、this.listModel.remove( idx )で削除しています。

ここでは、新しくオーバーライドしたactionPerformedを使い、 この中でスーパークラスのactionPerformed(e)のイベント処理をを再利用しています。よって、 スーパークラスで行っているaddActionListenerの設定が邪魔になります。
(このままだと、スーパークラスからの呼び出しと、新しい設定による呼び出しで、2回実行してまうことになります。)
そこで、コンストラクタでスーパークラスで設定したActionListenerオブジェクトを、 removeActionListener(this)で、外してから 改めて、addActionListener(this)実行して、 このactionPerformedのあるオブジェクトを登録しています。
以下に上記プログラムのクラス図を示します。