SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

作って覚えるJavaプログラミングのススメ

Java入門 (5) - Swingにおけるイベント処理

作って覚えるJavaプログラミングのススメ 第5回

JFrame継承クラスにimplementsする

 今度は、アクションイベントが発生したら、JFrameに組み込んであるコンポーネントを操作して処理を実行させてみることにしましょう。JTextFieldに書いてあるテキストを使って、JLabelに表示をしてみます。

 そのために、作成したActionAdapterのactionPerformedメソッドを書き換えて、

public void actionPerformed(ActionEvent ev){
    String s = field.getText();
    label.setText("あなたは、" + s + "と書きました。");
}

 このようにしてみました。結果はどうでしょう? これは、コンパイルエラーになってコンパイルできないはずです。なぜなら、fieldやlabelといったコンポーネントがあるクラスと、actionPerformedメソッドがあるクラスは別のクラスだからです。fieldやlabelはSampleクラスのフィールドですから、AcrtionAdapterクラスでは、そのままでは利用できないのです。

 では、どうすればよいのでしょうか。この解決法はいろいろと考えられます。まず、ActionAdapterの中に、Sampleインスタンスを保管するフィールドを用意しておけばいいんじゃないか、と思う人も多いことでしょう。Sampleインスタンスは、newする際に使用するインスタンスを受け渡すようにしておけば、うまくいきそうです。

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));
        this.add(button);
    }
    
    public static void main(String[] args) {
        Sample sample = new Sample();
        sample.setVisible(true);
    }
    
}

class ActionAdapter implements ActionListener {
    Sample sample;
    
    public ActionAdapter(Sample s){
        this.sample = s;
    }
    
    public void actionPerformed(ActionEvent ev){
        String s = sample.field.getText();
        sample.label.setText("あなたは、" + s + "と書きました。");
    }
}
フィールドにテキストを書いてボタンを押すと、メッセージがラベルに表示されるようになった。
フィールドにテキストを書いてボタンを押すと、メッセージがラベルに表示されるようになった。

 ここでは、ActionAdapterクラスの中にSampleインスタンスを保管するsampleフィールドを用意しておきました。そしてインスタンスを作成する際にコンストラクタで引数のSampleをフィールドに保管しておきます。ActionAdapterのコンストラクタを見てみましょう。

public ActionAdapter(Sample s){
    this.sample = s;
}

 このように、引数で渡されたSampleインスタンスをフィールドに保管しています。sampleフィールドは、単純にsampleと書くだけでもいいんですが、「このインスタンスの中にあるsampleですよ」ということがわかるように、this.sampleと書いてあります。インスタンス内のフィールドは、こんな具合にして指定できるのですね。

 そして、actionPerformedでは、このsampleに収めたインスタンスを利用してコンポーネントを操作しています。これは、sample内のフィールドのメソッドを呼び出す、という形になります。

String s = sample.field.getText();
sample.label.setText("あなたは、" + s + "と書きました。");

 sampleフィールドの中にはSampleインスタンスが収めてあります。この中のfieldやlabelフィールドのメソッドを呼び出して、コンポーネントを扱っているのです。sample.field.getTextというように、ちょっと長ったらしい書き方となってしまいますが、これでメソッドを呼び出すことはできるのです。

 後は、このActionAdapterのインスタンスを作成するときにSampleインスタンスを引数に指定するように修正するだけです。

button.addActionListener(new ActionAdapter(this));

 thisは、このインスタンス自身を示すものでした。これで、Sampleインスタンス自身を引数にしてActionAdapterインスタンスが作成されます。そして、作成したActionAdapterのsampleフィールドには引数のthisが設定され、このthisにあるコンポーネントを操作するようになる、というわけです。

JFrame継承クラスにimplementsする

 今の方法では、JFrameのインスタンスを引数に渡したり、フィールドにインスタンスを保管して操作するためのソースを大幅に修正しなければいけなくなります。これではちょっと面倒です。もっと手軽で簡単に利用する方法はないのでしょうか。

 最も広く用いられているのは、SampleクラスそのものにActionListenerをimplementsしてしまう、というものです。わざわざ独立したクラスを作らずに、Sampleに兼用させてしまえばよい、という考え方です。

package codezine.java;

import java.awt.event.*;
import javax.swing.*;

public class Sample extends JFrame 
        implements ActionListener {
    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(this);
        this.add(button);
    }

    public void actionPerformed(ActionEvent ev){
        String s = field.getText();
        label.setText("あなたは、" + s + "と書きました。");
    }
    
    public static void main(String[] args) {
        Sample sample = new Sample();
        sample.setVisible(true);
    }

}

 見れば分かるように、Sampleクラスがclass Sample extends JFrame implements ActionListenerという形になっています。implementsは、extendsで継承をしているクラスでも組み込むことができます。こうやってSampleクラス自身に組み込んでしまえば一番簡単です。

 ボタンにaddActionListenerしている部分を見ると、button.addActionListener(this);というようになっています。thisはこのインスタンス自身を示すものでした。これで、自分自身をアクションリスナーとして組み込むことができます。

 この方法は、ちょっとしたイベント処理を用意するのに最も手軽な方法です。ただし、利用するイベントリスナーが多くなってくると、1つのクラスの中に一切合財詰め込むというやり方はあまりお勧めできなくなります。1つのクラスがやたらと複雑になってしまっては、プログラムも読みにくくなりますし、後々のメンテナンスもやりにくくなるものです。なにより、この方法では1つのイベントリスナーについて1つしかクラスを定義できません。例えば複数のボタンに複数のActionListenerを設定する、というような場合は、このやり方は使えません。

次のページ
内部クラスを使った方法

この記事は参考になりましたか?

作って覚えるJavaプログラミングのススメ連載記事一覧

もっと読む

この記事の著者

掌田 津耶乃(ショウダ ツヤノ)

三文ライター&三流プログラマ。主にビギナーに向けたプログラミング関連の執筆を中心に活動している。※現在、入門ドキュメントサイト「libro」、カード型学習サイト「CARD.tuyano.com」を公開...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2194 2008/02/21 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー