Java超|GUIイベント処理の基本

ボタンが押された瞬間、画面が反応する。GUIイベント処理を学ぶと、Javaの画面は「表示するだけの窓」から「ユーザー操作に応じて動くアプリ」へ進化します。

GUIアプリケーションでは、ウィンドウやボタンを表示するだけでは、まだ本格的に使えるアプリとはいえません。

たとえば、画面にボタンがあっても、そのボタンを押したときに何も起こらなければ、ユーザーは何のためのボタンなのか分かりません。

GUIアプリでは、ユーザーが何か操作したときに、それに合わせて画面や処理が反応することが大切です。

たとえば、次のような動きです。

ユーザーの操作アプリ側の反応
ボタンを押す表示文字が変わる
キーを押す入力内容を受け取る
マウスを動かす位置に応じて反応する
ウィンドウを閉じるアプリを終了する

この「ユーザー操作をきっかけに処理が動くしくみ」が、イベント処理です。

ドラゴンボール風にたとえると、戦士本部の修行装置に「修行をはじめる」というボタンがあるとします。

そのボタンを押した瞬間に、修行案内盤の表示が「気を高めています」に切り替わる。

あるいは、停止ボタンを押したら修行装置が終了する。

このように、何かの操作を合図として装置が反応するのが、イベント処理のイメージです。

これまでの文字中心のプログラムでは、処理は上から下へ順番に進むことが多くありました。

表示する
  ↓
入力する
  ↓
計算する
  ↓
結果を表示する

一方、GUIアプリでは、ユーザーがいつボタンを押すか、いつウィンドウを閉じるかは決まっていません。

そのため、あらかじめ「この操作が起きたら、この処理を行う」と登録しておく必要があります。

この記事では、ボタンを押すとボタン上の文字が変わる Sample3.java を使い、イベント、ソース、リスナ、addActionListener、ActionListener、actionPerformed、ActionEvent の役割を、ドラゴンボールの世界観で整理していきます。

イベントとは何か

イベントとは、GUI上で起きる出来事のことです。

特に、ユーザーの操作がきっかけになることが多いです。

操作発生するイベントの例
ボタンを押すボタン操作のイベント
キーを押すキーボードのイベント
マウスを動かすマウス移動のイベント
ウィンドウを閉じるウィンドウ終了のイベント

ドラゴンボール風に言えば、イベントは「修行装置に変化を起こす合図」です。

たとえば、BulmaSupport が修行開始ボタンを押す。
GokuWarrior が重力修行の切り替えボタンを押す。
GohanAnalyzer が停止ボタンを押す。

このような操作が合図になり、修行装置や案内盤が反応します。

GUIでは、プログラムが一方的に進むだけではありません。

ユーザーの操作を待ち、その操作が起きたときに必要な処理を動かすという考え方になります。

イベント処理とは何か

イベント処理とは、イベントが起きたときに、それに応じて実行する処理のことです。

たとえば、次のようなものです。

イベントイベント処理
ボタンが押されたボタンの文字を変える
チェックボックスが選ばれた表示内容を切り替える
入力欄に文字が入った入力内容を確認する
ウィンドウが閉じられたアプリを終了する

今回の Sample3.java では、ボタンが押されたときに、ボタン上の文字を変更します。

最初は、ボタンに次の文字が表示されています。

修行をはじめる

ボタンを押すと、次の文字に変わります。

気を高めています

ドラゴンボール風に言えば、修行開始ボタンを押した瞬間に、案内盤の表示が「修行開始前」から「集中中」に切り替わるようなものです。

このように、GUIイベント処理では、ユーザーの操作をきっかけに、画面の状態や内部処理を変化させます。

イベント処理で登場する3つの役割

イベント処理では、まず次の3つの役割を押さえると分かりやすくなります。

役割内容今回の例
ソースイベントが発生する側Button
イベント実際に起きた出来事ボタンが押されたこと
リスナイベントを受け取って処理する側ActionListenerを実装したクラス

今回のボタン操作では、Button がイベントの発生元です。

ボタンが押されると、イベントが発生します。

そして、そのイベントを受け取る担当がリスナです。

ドラゴンボール風に置き換えると、次のようになります。

イベント処理の用語ドラゴンボール風のイメージ
ソース修行開始ボタン
イベント修行開始ボタンが押された合図
リスナ合図を受け取る制御係
actionPerformed制御係が実際に行う処理

ここで大切なのは、ボタンそのものが処理内容をすべて知っているわけではないということです。

ボタンは押されたことを知らせます。

その知らせを受け取って、リスナが処理を実行します。

図:イベント処理の基本構造

この図が示していること

この図では、GUIイベント処理の基本構造を表しています。

Button がソースとしてイベントを発生させます。

ボタンが押されると ActionEvent が発生し、登録されている ActionListener に通知されます。

そして、ActionListener の actionPerformed が呼ばれ、画面の表示が変わります。

図の要素意味
Buttonイベントが発生する部品
ActionEventボタンが押されたという出来事の情報
ActionListenerイベントを受け取る処理担当
actionPerformedイベント発生時に実行されるメソッド
表示の変化イベント処理の結果

この図から分かることは、GUIでは「ユーザー操作 → イベント発生 → リスナへ通知 → 処理実行」という流れで画面が反応するということです。

ボタンの文字を切り替える例

ここでは、ボタンを押すと、ボタン上の文字が変わるプログラムを見ていきます。

ファイル名:Sample3.java

import java.awt.*;
import java.awt.event.*;

public class Sample3 extends Frame
{
    private Button bt;

    public static void main(String[] args)
    {
        Sample3 sm = new Sample3();
    }

    public Sample3()
    {
        super("戦士本部 修行スタート画面");

        // ボタンを作成する
        bt = new Button("修行をはじめる");

        // フレームにボタンを追加する
        add(bt);

        addWindowListener(new SampleWindowListener());

        // ボタンが押されたときの処理を登録する
        bt.addActionListener(new SampleActionListener());

        setSize(320, 200);
        setVisible(true);
    }

    class SampleWindowListener extends WindowAdapter
    {
        public void windowClosing(WindowEvent e)
        {
            System.exit(0);
        }
    }

    class SampleActionListener implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            bt.setLabel("気を高めています");
        }
    }
}

このプログラムでできること

このプログラムを実行すると、「戦士本部 修行スタート画面」というタイトルのウィンドウが表示されます。

ウィンドウの中には、「修行をはじめる」と書かれたボタンが表示されます。

そのボタンをクリックすると、ボタン上の文字が「気を高めています」に変わります。

さらに、ウィンドウの閉じるボタンを押すと、アプリケーションが終了します。

操作結果
アプリを起動するボタンが表示される
ボタンを押すボタンの文字が変わる
閉じるボタンを押すアプリケーションが終了する

この小さなプログラムには、GUIイベント処理の基本がしっかり入っています。

ボタンを作る。
ボタンをウィンドウに置く。
ボタンが押されたときの処理担当を登録する。
ボタンが押されたら actionPerformed が呼ばれる。
その中でボタンの文字を変える。

この流れが、イベント処理の最初の大切な形です。

Buttonでボタンを作る

ボタンは Button クラスで作ります。

Sample3.java では、次のように書いています。

bt = new Button("修行をはじめる");

このコードによって、「修行をはじめる」と表示されたボタンオブジェクトが作られます。

部分意味
btButtonオブジェクトを指す変数
new Button(...)ボタンを作る
"修行をはじめる"ボタンに表示される文字

ただし、ボタンを作っただけでは画面には表示されません。

画面に表示するためには、Frameに追加する必要があります。

add(bt);

この add(bt) によって、ボタンがウィンドウに配置されます。

コード役割
new Button("修行をはじめる")ボタンを作る
add(bt)ボタンをウィンドウに追加する

ドラゴンボール風に言えば、new Button は「修行をはじめる」と書かれた操作ボタンを作る作業です。

add(bt) は、その操作ボタンを修行案内盤に取り付ける作業です。

操作ボタンを作っただけで机の上に置いていても、戦士は使えません。

案内盤に取り付けることで、はじめてユーザーが押せるボタンになります。

ボタンを置いただけでは反応しない

ここで大切なのは、ボタンを作って配置しただけでは、まだ「押されたときの処理」は決まっていないということです。

bt = new Button("修行をはじめる");
add(bt);

この段階で、ボタンは画面に表示されます。

しかし、押されたときに何をするかは、まだ登録されていません。

GUIイベント処理では、ボタンに対して「押されたら誰に知らせるか」を登録する必要があります。

その登録を行うのが addActionListener です。

addActionListenerで処理担当を登録する

Sample3.java では、次の1行でボタンにリスナを登録しています。

bt.addActionListener(new SampleActionListener());

これは、次のような意味です。

このボタンが押されたら、SampleActionListener に知らせてください。

つまり、Button と ActionListener を結びつけているのが addActionListener です。

部分役割
btイベントを発生させるボタン
addActionListenerボタンと処理担当を結びつける
new SampleActionListener()イベントを受け取るリスナオブジェクト

ドラゴンボール風に言えば、修行開始ボタンに「押されたら BulmaSupport の制御係へ連絡する」という連絡経路をつないでいる状態です。

この登録がないと、ボタンが押されても、どの処理担当に知らせればよいのか分かりません。

図:addActionListenerでソースとリスナを結びつける

この図が示していること

この図では、addActionListener が Button と SampleActionListener を結びつける役割を持つことを表しています。

Button はイベントを発生させるソースです。

SampleActionListener は、そのイベントを受け取って処理するリスナです。

addActionListener を使うことで、「このボタンが押されたら、このリスナに知らせる」という関係が作られます。

図の要素意味
Button btイベントの発生元
SampleActionListenerイベント処理の担当
addActionListenerソースとリスナを結びつける登録
actionPerformedボタンが押されたときに呼ばれる処理
接続線ボタンとリスナの関連付け

この図から分かることは、イベント処理では、部品を置くだけでなく、部品と処理担当を結びつける登録が必要だということです。

ActionListenerとは何か

ActionListener は、ボタン操作のようなアクションイベントを受け取るためのインターフェイスです。

Sample3.java では、内部クラス SampleActionListener が ActionListener を実装しています。

class SampleActionListener implements ActionListener
{
    public void actionPerformed(ActionEvent e)
    {
        bt.setLabel("気を高めています");
    }
}

このクラスは、ボタンが押されたときの処理担当です。

ActionListener を実装するクラスでは、actionPerformed を定義します。

要素役割
implements ActionListenerボタン操作を受け取る約束をする
actionPerformedイベントが起きたときに実行されるメソッド
ActionEvent e発生したイベントの情報を受け取る引数

ドラゴンボール風に言えば、ActionListener は「修行開始ボタンが押されたときに反応できる制御係になるための約束」です。

SampleActionListener は、その約束を守る制御係です。

そして、actionPerformed は、実際に制御係が行う処理です。

actionPerformedが呼ばれるタイミング

actionPerformed は、自分で直接呼ぶためのメソッドではありません。

ボタンが押され、イベントが発生し、そのボタンに登録されているリスナへ通知されたときに、自動的に呼ばれます。

流れは次のようになります。

順番起こること
1ユーザーがボタンを押す
2Button がイベントを発生させる
3登録済みの SampleActionListener に通知される
4actionPerformed が呼ばれる
5bt.setLabel が実行される
6ボタンの文字が変わる

今回の actionPerformed の中身は、次の1行です。

bt.setLabel("気を高めています");

この処理によって、ボタンの表示文字が変わります。

ドラゴンボール風に言えば、GokuWarrior が修行開始ボタンを押す。

その合図が BulmaSupport の制御係に届く。

制御係が案内盤の表示を「気を高めています」に切り替える。

このような流れです。

setLabelでボタンの文字を変更する

Button の表示文字は、setLabel で変更できます。

Sample3.java では、次のように書いています。

bt.setLabel("気を高めています");

最初に作ったボタンは、次の表示でした。

bt = new Button("修行をはじめる");

ボタンを押すと、actionPerformed の中で setLabel が実行され、表示が変わります。

状態ボタンの表示
起動直後修行をはじめる
ボタンを押した後気を高めています

setLabel は、画面の見た目をイベントに応じて変更する分かりやすい例です。

GUIアプリでは、イベント処理の中で、文字、色、表示内容、状態などを変えることがよくあります。

ドラゴンボール風に言えば、修行開始ボタンを押したことで、案内表示が「開始前」から「集中中」に切り替わったようなものです。

ActionEventの役割

actionPerformed の引数には、ActionEvent e があります。

public void actionPerformed(ActionEvent e)

ActionEvent は、発生したイベントの情報を表すオブジェクトです。

今回のプログラムでは e を直接使っていません。

しかし、ActionEvent の中には「どの操作が起きたのか」という情報が入っています。

要素役割
ActionEventアクションイベントの情報を持つオブジェクト
e発生したイベント情報を受け取る変数
actionPerformed(ActionEvent e)イベント情報を受け取りながら処理する形

学習の最初では、まず次のように理解すれば十分です。

ボタンが押されると actionPerformed が呼ばれ、そのとき ActionEvent が渡される。

今後、複数のボタンを扱うときには、ActionEvent の情報を使って、どのボタンが押されたかを判断することもあります。

ドラゴンボール風に言えば、ActionEvent は「どの操作ボタンが押されたのかを記した通知札」です。

ウィンドウを閉じるイベントも処理している

Sample3.java では、ボタンイベントだけでなく、ウィンドウを閉じるイベントにも対応しています。

addWindowListener(new SampleWindowListener());

そして、SampleWindowListener は WindowAdapter を継承しています。

class SampleWindowListener extends WindowAdapter
{
    public void windowClosing(WindowEvent e)
    {
        System.exit(0);
    }
}

この処理によって、ユーザーがウィンドウの閉じるボタンを押したときに、アプリケーションを終了できます。

要素役割
WindowAdapterウィンドウイベントを扱いやすくする補助クラス
windowClosingウィンドウを閉じる操作が起きたときに呼ばれる
WindowEvent eウィンドウイベントの情報
System.exit(0)アプリケーションを終了する

ドラゴンボール風に言えば、修行案内盤の停止ボタンが押されたときに、戦士本部の BulmaSupport が装置を安全に停止するようなものです。

GUIでは、ボタン操作だけでなく、ウィンドウ操作もイベントとして扱われます。

プログラム全体の流れ

Sample3.java の全体の流れを整理すると、次のようになります。

順番処理ドラゴンボール風のイメージ
1Frameを継承したSample3を作る修行画面の土台を作る
2mainでSample3オブジェクトを作る修行スタート画面を起動する
3Buttonを作る修行開始ボタンを作る
4addでButtonをFrameに追加する修行開始ボタンを案内盤に取り付ける
5WindowListenerを登録する停止ボタンに反応できるようにする
6ActionListenerを登録する修行開始ボタンの連絡先を設定する
7setSizeで大きさを決める案内盤の大きさを決める
8setVisibleで表示する画面に出す
9ボタンが押される修行開始ボタンが押される
10actionPerformedが呼ばれる制御係が合図を受け取る
11setLabelで文字を変える案内表示を切り替える

この流れを見ると、GUIイベント処理では、事前準備とイベント発生後の処理が分かれていることが分かります。

段階内容
事前準備ボタンを作る、配置する、リスナを登録する
イベント発生後actionPerformed が呼ばれ、処理が実行される

ボタンを押す前から、処理がすぐに実行されるわけではありません。

ボタンが押されたタイミングで、登録済みのリスナが呼ばれます。

図:ボタンを押して表示が変わるまで

この図が示していること

この図では、ボタンを押してから表示が変わるまでの流れを順番に表しています。

最初に画面には「修行をはじめる」というボタンが表示されています。

ユーザーがそのボタンを押すと、ActionEvent が発生します。

そのイベントが登録済みの SampleActionListener に通知され、actionPerformed が呼ばれます。

最後に、bt.setLabel によってボタンの文字が「気を高めています」に変わります。

流れ内容
画面表示ボタンが表示されている
ユーザー操作ボタンが押される
イベント発生ActionEventが発生する
リスナ処理actionPerformedが呼ばれる
表示変更setLabelで文字が変わる

この図から分かることは、GUIイベント処理は、ユーザー操作を出発点として、登録済みの処理が自動的に呼び出されるしくみだということです。

ソースとリスナの関係

イベント処理では、ソースとリスナの関係がとても重要です。

ソースは、イベントが発生する側です。

今回なら、bt というボタンがソースです。

リスナは、イベントを受け取って処理する側です。

今回なら、SampleActionListener がリスナです。

用語今回の役割
ソースbt というButton
イベントボタンが押されたこと
リスナSampleActionListener
登録bt.addActionListener(new SampleActionListener())
処理メソッドactionPerformed

この関係は、GUIを学ぶうえで何度も登場します。

ボタンだけでなく、チェックボックス、リスト、テキスト入力、マウス操作などでも、基本は「ソースがイベントを出し、リスナが受け取る」という形です。

ドラゴンボール風に言えば、修行開始ボタンが合図を出し、制御係がその合図を受け取り、案内盤の表示を切り替える関係です。

addActionListenerをもう少しやさしく見る

addActionListener は、最初は少し分かりにくく感じるかもしれません。

bt.addActionListener(new SampleActionListener());

この文は、単に「見張るしくみを付ける」というより、次のように考えると分かりやすいです。

このボタンが押されたら、この処理担当に連絡してください。

つまり、ボタンと処理担当を関連付けています。

状態どうなるか
ボタンだけある押されても処理先が決まっていない
リスナだけあるイベントを受け取る相手がまだ決まっていない
addActionListenerで登録するボタンが押されたときにリスナへ通知できる

ドラゴンボール風に言えば、修行開始ボタンと制御係を連絡札でつなぐようなものです。

連絡がつながっていれば、ボタンが押された瞬間に、制御係が動けます。

GUIではイベント処理が中心になる

GUIアプリケーションでは、画面を作ることも大切ですが、同じくらい大切なのが「操作にどう反応するか」です。

ボタンを表示するだけなら、静かな画面です。

しかし、ボタンを押したときに文字が変わると、ユーザーは「操作できた」と感じられます。

GUIでよくある操作イベント処理の例
ボタンを押すメッセージを表示する
入力欄に文字を書く入力内容を読み取る
チェックボックスを選ぶ表示内容を切り替える
リストから選ぶ選択した内容を反映する
ウィンドウを閉じるアプリを終了する

この先、GUIを学んでいくと、さまざまなコンポーネントとイベント処理が登場します。

でも、基本の形は今回と同じです。

部品を作る
  ↓
画面に追加する
  ↓
リスナを登録する
  ↓
イベントが起きる
  ↓
処理メソッドが呼ばれる

この流れが分かると、GUIイベント処理がかなり見えやすくなります。

はじめてイベント処理を学ぶときに戸惑いやすい点

イベント処理は、これまでの上から順番に進むプログラムとは少し感覚が違います。

そのため、最初は次の点で戸惑いやすいです。

戸惑いやすい点理由
ボタンを押したときの処理が離れた場所にあるactionPerformedが内部クラスに書かれているため
addActionListenerの意味が分かりにくい登録という考え方に慣れていないため
actionPerformedが自動的に呼ばれるように見えるイベント発生時にAWT側が呼び出すため
ソースとリスナの関係が見えにくい発生する側と処理する側が分かれているため
ActionEvent eを使っていないのが気になる今回はイベント情報を直接使わなくても処理できるため

しかし、次の形で覚えると理解しやすくなります。

基本形内容
部品を作るButtonを作る
部品を置くaddでFrameに追加する
リスナを用意するActionListenerを実装する
リスナを登録するaddActionListenerを使う
イベントが起きるボタンが押される
処理が動くactionPerformedが呼ばれる

ドラゴンボール風に言えば、修行開始ボタンを作って案内盤に取り付け、BulmaSupport の制御係と連絡をつなぎ、ボタンが押されたら制御係が動く、という流れです。

Sample3.javaで大切な要素

今回のテーマで特に大切な要素を整理すると、次のようになります。

要素意味
Buttonイベントの発生元になる部品
addボタンをFrameに追加する
addActionListenerボタンとリスナを結びつける
ActionListenerボタン操作を受け取るためのしくみ
actionPerformedボタンが押されたときに実行される処理
ActionEvent発生したイベントの情報
setLabelボタン上の文字を変更する
WindowAdapterウィンドウを閉じる操作に対応する補助クラス

この流れが見えてくると、GUIアプリはただ画面を表示するだけではなく、人の操作に反応して変化するしくみでできていることが分かります。

Frame は画面の土台です。

Button は操作の入口です。

ActionListener は操作を受け取る担当です。

actionPerformed は、実際に反応する処理です。

そして addActionListener は、Button と ActionListener をつなぐ登録です。

ドラゴンボール風に言えば、修行案内盤に修行開始ボタンを取り付け、そのボタンと制御係をつなぎ、ボタンが押されたら案内表示を切り替える。

この一連の流れが、GUIイベント処理の基本です。